From 3ef37dc5773767866eda83d7283f6d11a02ec0e2 Mon Sep 17 00:00:00 2001 From: hymbz Date: Mon, 8 May 2023 22:57:31 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20:recycle:=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E7=BB=93=E6=9E=84=EF=BC=8C=E5=B0=86=E6=89=80?= =?UTF-8?q?=E6=9C=89=E4=BB=A3=E7=A0=81=E6=94=BE=E5=88=B0=E4=B8=80=E8=B5=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc.js => .eslintrc.cjs | 3 +- .gitignore | 1 - .../.postcssrc.cjs => .postcssrc.cjs | 0 .stylelintrc.js | 2 + ComicRead.user.js | 4853 ----------------- ComicReadScript.code-workspace | 26 - docs/Dev.md | 18 +- .../ui-component/index.html => index.html | 2 +- package.json | 74 +- packages/ui-component/.gitignore | 2 - packages/ui-component/README.md | 3 - packages/ui-component/build.ts | 249 - packages/ui-component/dev.ts | 249 - packages/ui-component/package.json | 77 - packages/ui-component/pnpm-lock.yaml | 945 ---- packages/ui-component/rollup-solid-svg.ts | 104 - .../components/Manga/components/Scrollbar.tsx | 64 - packages/ui-component/src/helper/import.ts | 112 - packages/ui-component/src/helper/index.ts | 212 - .../src/helper/setToolbarButton.tsx | 74 - .../ui-component/src/helper/useCache.test.ts | 74 - packages/ui-component/src/helper/useCache.ts | 101 - packages/ui-component/src/main.ts | 9 - packages/ui-component/src/site/dm5.tsx | 70 - packages/ui-component/src/site/test.tsx | 8 - packages/ui-component/src/types/index.d.ts | 51 - .../ui-component/src/types/tampermonkey.d.ts | 765 --- .../ui-component/src/useComponents/Fab.tsx | 55 - .../ui-component/src/useComponents/Manga.tsx | 77 - .../ui-component/src/useComponents/Toast.tsx | 14 - packages/ui-component/tsconfig.json | 10 - packages/ui-component/vite.config.ts | 38 - packages/userscript/.vscode/launch.json | 14 - packages/userscript/package.json | 49 - packages/userscript/resource.json | 18 - packages/userscript/rollup.config.ts | 274 - packages/userscript/src/components/Manga.tsx | 83 - packages/userscript/src/components/Toast.tsx | 15 - packages/userscript/src/dev.ts | 15 - .../src/helper/defaultSpeedDial.tsx | 60 - packages/userscript/src/helper/index.ts | 9 - .../src/helper/setToolbarButton.tsx | 76 - packages/userscript/src/helper/useInit.tsx | 198 - .../userscript/src/helper/useSiteOptions.ts | 65 - packages/userscript/src/index.tsx | 8 - packages/userscript/src/site/copymanga.tsx | 32 - packages/userscript/src/site/dmzj.tsx | 219 - packages/userscript/src/site/dmzj_phone.tsx | 171 - .../userscript/src/site/dmzj_user_info.tsx | 241 - packages/userscript/src/site/dmzj_www.tsx | 17 - packages/userscript/src/site/ehentai.tsx | 294 - packages/userscript/src/site/jm.tsx | 63 - packages/userscript/src/site/mangabz.tsx | 56 - packages/userscript/src/site/manhuaDB.tsx | 48 - packages/userscript/src/site/manhuacat.tsx | 43 - packages/userscript/src/site/manhuagui.tsx | 31 - packages/userscript/src/site/newYamibo.tsx | 58 - packages/userscript/src/site/nhentai.tsx | 222 - packages/userscript/src/site/other.tsx | 125 - packages/userscript/src/site/test.tsx | 8 - packages/userscript/src/site/yamibo.tsx | 383 -- packages/userscript/src/types/index.d.ts | 16 - packages/userscript/tsconfig.json | 7 - pnpm-lock.yaml | 1875 +++++-- pnpm-workspace.yaml | 2 - scripts/release.mjs => release.mjs | 0 rollup-solid-svg.ts | 63 + .../rollup.config.ts => rollup.config.ts | 117 +- .../src => src}/components/Fab/display.tsx | 0 .../components/Fab/index.module.css | 4 - .../src => src}/components/Fab/index.tsx | 2 - .../components/IconButton/display.tsx | 2 + .../components/IconButton/index.module.css | 6 +- .../components/IconButton/index.tsx | 2 +- .../Manga/components/ComicImg.module.css | 17 - .../components/Manga/components/ComicImg.tsx | 1 + .../Manga/components/ComicImgFlow.tsx | 2 +- .../components/Manga/components/EndPage.tsx | 3 +- .../Manga/components/Scrollbar.module.css | 12 +- src/components/Manga/components/Scrollbar.tsx | 83 + .../Manga/components/Setting.module.css | 4 - .../Manga/components/SettingPanel.tsx | 4 +- .../Manga/components/SettingsItem.tsx | 0 .../Manga/components/SettingsItemSwitch.tsx | 1 + .../Manga/components/Toolbar.module.css | 0 .../components/Manga/components/Toolbar.tsx | 4 +- .../Manga/components/TouchArea.module.css | 0 .../components/Manga/components/TouchArea.tsx | 3 +- .../components/Manga/defaultButtonList.tsx | 19 +- .../components/Manga/defaultSettingList.tsx | 51 +- .../src => src}/components/Manga/display.tsx | 4 - .../components/Manga/handleComicData.test.ts | 41 +- .../components/Manga/handleComicData.ts | 7 +- .../src => src}/components/Manga/helper.ts | 0 .../components/Manga/hooks/useCssVar.ts | 1 + .../components/Manga/hooks/useDoubleClick.ts | 0 .../components/Manga/hooks/useDrag.ts | 1 + .../components/Manga/hooks/useFocus.ts | 0 .../components/Manga/hooks/useHover.ts | 0 .../components/Manga/hooks/useInit.ts | 19 +- .../Manga/hooks/useStore/ExternalLibState.ts | 0 .../Manga/hooks/useStore/ImageState.ts | 6 +- .../Manga/hooks/useStore/OperateState.ts | 2 +- .../Manga/hooks/useStore/OptionState.ts | 0 .../Manga/hooks/useStore/OtherState.ts | 0 .../Manga/hooks/useStore/ScrollbarState.ts | 0 .../components/Manga/hooks/useStore/index.ts | 5 +- .../Manga/hooks/useStore/slice/ExternalLib.ts | 0 .../Manga/hooks/useStore/slice/Image.ts | 52 +- .../Manga/hooks/useStore/slice/Operate.ts | 10 +- .../Manga/hooks/useStore/slice/Option.ts | 10 + .../Manga/hooks/useStore/slice/Scrollbar.ts | 22 +- .../Manga/hooks/useStore/slice/index.ts | 1 + .../components/Manga/index.module.css | 0 .../src => src}/components/Manga/index.tsx | 11 +- .../src => src/components}/display.tsx | 2 +- .../components/useComponents}/Fab.tsx | 45 +- src/components/useComponents/Manga.tsx | 143 + src/components/useComponents/Toast.tsx | 58 + src/components/useComponents/toast.module.css | 73 + {packages/ui-component/src => src}/dev.ts | 2 +- .../userscript/src => src}/helper/import.ts | 32 +- .../helper/utils.ts => src/helper/index.ts | 18 +- .../src => src}/helper/useCache.test.ts | 1 - .../userscript/src => src}/helper/useCache.ts | 1 + .../src => src}/helper/useInit.tsx | 35 +- .../src => src}/helper/useSiteOptions.ts | 2 - .../helper/useSpeedDial.tsx | 37 +- {packages/ui-component/src => src}/index.ts | 0 src/main.ts | 10 + .../src => src}/site/copymanga.tsx | 0 {packages/userscript/src => src}/site/dm5.tsx | 10 +- .../ui-component/src => src}/site/dmzj.tsx | 0 .../src => src}/site/dmzj_phone.tsx | 0 .../src => src}/site/dmzj_user_info.tsx | 1 - .../src => src}/site/dmzj_www.tsx | 0 .../ui-component/src => src}/site/ehentai.tsx | 5 +- .../ui-component/src => src}/site/jm.tsx | 13 +- .../ui-component/src => src}/site/mangabz.tsx | 0 .../src => src}/site/manhuaDB.tsx | 0 .../src => src}/site/manhuacat.tsx | 0 .../src => src}/site/manhuagui.tsx | 0 .../src => src}/site/newYamibo.tsx | 0 .../ui-component/src => src}/site/nhentai.tsx | 5 +- .../ui-component/src => src}/site/other.tsx | 37 +- .../ui-component/src => src}/site/yamibo.tsx | 40 +- src/types/index.d.ts | 27 + .../src => src}/types/tampermonkey.d.ts | 28 +- .../src => src}/types/vite-env.d.ts | 0 tsconfig.base.json => tsconfig.json | 6 +- 150 files changed, 2201 insertions(+), 12159 deletions(-) rename .eslintrc.js => .eslintrc.cjs (98%) rename packages/ui-component/.postcssrc.cjs => .postcssrc.cjs (100%) delete mode 100644 ComicRead.user.js delete mode 100644 ComicReadScript.code-workspace rename packages/ui-component/index.html => index.html (89%) delete mode 100644 packages/ui-component/.gitignore delete mode 100644 packages/ui-component/README.md delete mode 100644 packages/ui-component/build.ts delete mode 100644 packages/ui-component/dev.ts delete mode 100644 packages/ui-component/package.json delete mode 100644 packages/ui-component/pnpm-lock.yaml delete mode 100644 packages/ui-component/rollup-solid-svg.ts delete mode 100644 packages/ui-component/src/components/Manga/components/Scrollbar.tsx delete mode 100644 packages/ui-component/src/helper/import.ts delete mode 100644 packages/ui-component/src/helper/index.ts delete mode 100644 packages/ui-component/src/helper/setToolbarButton.tsx delete mode 100644 packages/ui-component/src/helper/useCache.test.ts delete mode 100644 packages/ui-component/src/helper/useCache.ts delete mode 100644 packages/ui-component/src/main.ts delete mode 100644 packages/ui-component/src/site/dm5.tsx delete mode 100644 packages/ui-component/src/site/test.tsx delete mode 100644 packages/ui-component/src/types/index.d.ts delete mode 100644 packages/ui-component/src/types/tampermonkey.d.ts delete mode 100644 packages/ui-component/src/useComponents/Fab.tsx delete mode 100644 packages/ui-component/src/useComponents/Manga.tsx delete mode 100644 packages/ui-component/src/useComponents/Toast.tsx delete mode 100644 packages/ui-component/tsconfig.json delete mode 100644 packages/ui-component/vite.config.ts delete mode 100644 packages/userscript/.vscode/launch.json delete mode 100644 packages/userscript/package.json delete mode 100644 packages/userscript/resource.json delete mode 100644 packages/userscript/rollup.config.ts delete mode 100644 packages/userscript/src/components/Manga.tsx delete mode 100644 packages/userscript/src/components/Toast.tsx delete mode 100644 packages/userscript/src/dev.ts delete mode 100644 packages/userscript/src/helper/defaultSpeedDial.tsx delete mode 100644 packages/userscript/src/helper/index.ts delete mode 100644 packages/userscript/src/helper/setToolbarButton.tsx delete mode 100644 packages/userscript/src/helper/useInit.tsx delete mode 100644 packages/userscript/src/helper/useSiteOptions.ts delete mode 100644 packages/userscript/src/index.tsx delete mode 100644 packages/userscript/src/site/copymanga.tsx delete mode 100644 packages/userscript/src/site/dmzj.tsx delete mode 100644 packages/userscript/src/site/dmzj_phone.tsx delete mode 100644 packages/userscript/src/site/dmzj_user_info.tsx delete mode 100644 packages/userscript/src/site/dmzj_www.tsx delete mode 100644 packages/userscript/src/site/ehentai.tsx delete mode 100644 packages/userscript/src/site/jm.tsx delete mode 100644 packages/userscript/src/site/mangabz.tsx delete mode 100644 packages/userscript/src/site/manhuaDB.tsx delete mode 100644 packages/userscript/src/site/manhuacat.tsx delete mode 100644 packages/userscript/src/site/manhuagui.tsx delete mode 100644 packages/userscript/src/site/newYamibo.tsx delete mode 100644 packages/userscript/src/site/nhentai.tsx delete mode 100644 packages/userscript/src/site/other.tsx delete mode 100644 packages/userscript/src/site/test.tsx delete mode 100644 packages/userscript/src/site/yamibo.tsx delete mode 100644 packages/userscript/src/types/index.d.ts delete mode 100644 packages/userscript/tsconfig.json delete mode 100644 pnpm-workspace.yaml rename scripts/release.mjs => release.mjs (100%) create mode 100644 rollup-solid-svg.ts rename packages/ui-component/rollup.config.ts => rollup.config.ts (73%) rename {packages/ui-component/src => src}/components/Fab/display.tsx (100%) rename {packages/ui-component/src => src}/components/Fab/index.module.css (99%) rename {packages/ui-component/src => src}/components/Fab/index.tsx (98%) rename {packages/ui-component/src => src}/components/IconButton/display.tsx (99%) rename {packages/ui-component/src => src}/components/IconButton/index.module.css (98%) rename {packages/ui-component/src => src}/components/IconButton/index.tsx (97%) rename {packages/ui-component/src => src}/components/Manga/components/ComicImg.module.css (93%) rename {packages/ui-component/src => src}/components/Manga/components/ComicImg.tsx (99%) rename {packages/ui-component/src => src}/components/Manga/components/ComicImgFlow.tsx (100%) rename {packages/ui-component/src => src}/components/Manga/components/EndPage.tsx (99%) rename {packages/ui-component/src => src}/components/Manga/components/Scrollbar.module.css (86%) create mode 100644 src/components/Manga/components/Scrollbar.tsx rename {packages/ui-component/src => src}/components/Manga/components/Setting.module.css (99%) rename {packages/ui-component/src => src}/components/Manga/components/SettingPanel.tsx (100%) rename {packages/ui-component/src => src}/components/Manga/components/SettingsItem.tsx (100%) rename {packages/ui-component/src => src}/components/Manga/components/SettingsItemSwitch.tsx (99%) rename {packages/ui-component/src => src}/components/Manga/components/Toolbar.module.css (100%) rename {packages/ui-component/src => src}/components/Manga/components/Toolbar.tsx (100%) rename {packages/ui-component/src => src}/components/Manga/components/TouchArea.module.css (100%) rename {packages/ui-component/src => src}/components/Manga/components/TouchArea.tsx (99%) rename {packages/ui-component/src => src}/components/Manga/defaultButtonList.tsx (88%) rename {packages/ui-component/src => src}/components/Manga/defaultSettingList.tsx (81%) rename {packages/ui-component/src => src}/components/Manga/display.tsx (99%) rename {packages/ui-component/src => src}/components/Manga/handleComicData.test.ts (70%) rename {packages/ui-component/src => src}/components/Manga/handleComicData.ts (85%) rename {packages/ui-component/src => src}/components/Manga/helper.ts (100%) rename {packages/ui-component/src => src}/components/Manga/hooks/useCssVar.ts (99%) rename {packages/ui-component/src => src}/components/Manga/hooks/useDoubleClick.ts (100%) rename {packages/ui-component/src => src}/components/Manga/hooks/useDrag.ts (99%) rename {packages/ui-component/src => src}/components/Manga/hooks/useFocus.ts (100%) rename {packages/ui-component/src => src}/components/Manga/hooks/useHover.ts (100%) rename {packages/ui-component/src => src}/components/Manga/hooks/useInit.ts (89%) rename {packages/ui-component/src => src}/components/Manga/hooks/useStore/ExternalLibState.ts (100%) rename {packages/ui-component/src => src}/components/Manga/hooks/useStore/ImageState.ts (82%) rename {packages/ui-component/src => src}/components/Manga/hooks/useStore/OperateState.ts (81%) rename {packages/ui-component/src => src}/components/Manga/hooks/useStore/OptionState.ts (100%) rename {packages/ui-component/src => src}/components/Manga/hooks/useStore/OtherState.ts (100%) rename {packages/ui-component/src => src}/components/Manga/hooks/useStore/ScrollbarState.ts (100%) rename {packages/ui-component/src => src}/components/Manga/hooks/useStore/index.ts (89%) rename {packages/ui-component/src => src}/components/Manga/hooks/useStore/slice/ExternalLib.ts (100%) rename {packages/ui-component/src => src}/components/Manga/hooks/useStore/slice/Image.ts (90%) rename {packages/ui-component/src => src}/components/Manga/hooks/useStore/slice/Operate.ts (93%) create mode 100644 src/components/Manga/hooks/useStore/slice/Option.ts rename {packages/ui-component/src => src}/components/Manga/hooks/useStore/slice/Scrollbar.ts (92%) rename {packages/ui-component/src => src}/components/Manga/hooks/useStore/slice/index.ts (81%) rename {packages/ui-component/src => src}/components/Manga/index.module.css (100%) rename {packages/ui-component/src => src}/components/Manga/index.tsx (97%) rename {packages/ui-component/src => src/components}/display.tsx (96%) rename {packages/userscript/src/components => src/components/useComponents}/Fab.tsx (60%) create mode 100644 src/components/useComponents/Manga.tsx create mode 100644 src/components/useComponents/Toast.tsx create mode 100644 src/components/useComponents/toast.module.css rename {packages/ui-component/src => src}/dev.ts (85%) rename {packages/userscript/src => src}/helper/import.ts (73%) rename packages/userscript/src/helper/utils.ts => src/helper/index.ts (92%) rename {packages/userscript/src => src}/helper/useCache.test.ts (98%) rename {packages/userscript/src => src}/helper/useCache.ts (99%) rename {packages/ui-component/src => src}/helper/useInit.tsx (86%) rename {packages/ui-component/src => src}/helper/useSiteOptions.ts (99%) rename packages/ui-component/src/helper/defaultSpeedDial.tsx => src/helper/useSpeedDial.tsx (62%) rename {packages/ui-component/src => src}/index.ts (100%) create mode 100644 src/main.ts rename {packages/ui-component/src => src}/site/copymanga.tsx (100%) rename {packages/userscript/src => src}/site/dm5.tsx (92%) rename {packages/ui-component/src => src}/site/dmzj.tsx (100%) rename {packages/ui-component/src => src}/site/dmzj_phone.tsx (100%) rename {packages/ui-component/src => src}/site/dmzj_user_info.tsx (99%) rename {packages/ui-component/src => src}/site/dmzj_www.tsx (100%) rename {packages/ui-component/src => src}/site/ehentai.tsx (98%) rename {packages/ui-component/src => src}/site/jm.tsx (88%) rename {packages/ui-component/src => src}/site/mangabz.tsx (100%) rename {packages/ui-component/src => src}/site/manhuaDB.tsx (100%) rename {packages/ui-component/src => src}/site/manhuacat.tsx (100%) rename {packages/ui-component/src => src}/site/manhuagui.tsx (100%) rename {packages/ui-component/src => src}/site/newYamibo.tsx (100%) rename {packages/ui-component/src => src}/site/nhentai.tsx (98%) rename {packages/ui-component/src => src}/site/other.tsx (83%) rename {packages/ui-component/src => src}/site/yamibo.tsx (92%) create mode 100644 src/types/index.d.ts rename {packages/userscript/src => src}/types/tampermonkey.d.ts (99%) rename {packages/ui-component/src => src}/types/vite-env.d.ts (100%) rename tsconfig.base.json => tsconfig.json (97%) diff --git a/.eslintrc.js b/.eslintrc.cjs similarity index 98% rename from .eslintrc.js rename to .eslintrc.cjs index ae82cf54..382f396a 100644 --- a/.eslintrc.js +++ b/.eslintrc.cjs @@ -9,7 +9,6 @@ const publicConfig = { singleQuote: true, trailingComma: 'all', htmlWhitespaceSensitivity: 'strict', - plugins: [require('prettier-plugin-tailwindcss')], }, ], @@ -83,7 +82,7 @@ module.exports = { parser: '@typescript-eslint/parser', parserOptions: { tsconfigRootDir: __dirname, - project: ['./packages/*/tsconfig.json'], + project: ['./tsconfig.json'], }, plugins: ['@typescript-eslint', 'jsdoc', 'solid'], extends: [ diff --git a/.gitignore b/.gitignore index eba19548..de4d1f00 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ dist node_modules -packages/ui-component/tsconfig.tsbuildinfo diff --git a/packages/ui-component/.postcssrc.cjs b/.postcssrc.cjs similarity index 100% rename from packages/ui-component/.postcssrc.cjs rename to .postcssrc.cjs diff --git a/.stylelintrc.js b/.stylelintrc.js index 1d25e2e5..8d00b694 100644 --- a/.stylelintrc.js +++ b/.stylelintrc.js @@ -21,5 +21,7 @@ module.exports = { // 防止使用低性能的动画和过度属性 'plugin/no-low-performance-animation-properties': true, + + 'import-notation': 'string', }, }; diff --git a/ComicRead.user.js b/ComicRead.user.js deleted file mode 100644 index c76f07eb..00000000 --- a/ComicRead.user.js +++ /dev/null @@ -1,4853 +0,0 @@ -// ==UserScript== -// @name comic-read-script -// @namespace comic-read-script -// @version 0.2.1 -// @author hymbz -// @license AGPL-3.0-or-later -// @noframes -// @match *://*/* -// @connect cdn.jsdelivr.net -// @connect yamibo.com -// @connect dmzj.com -// @connect idmzj.com -// @connect exhentai.org -// @connect e-hentai.org -// @connect nhentai.net -// @connect mangabz.com -// @connect copymanga.site -// @connect copymanga.info -// @connect copymanga.net -// @connect copymanga.org -// @connect copymanga.com -// @connect * -// @resource react https://unpkg.com/react@18.2.0/umd/react.production.min.js -// @resource react-dom https://unpkg.com/react-dom@18.2.0/umd/react-dom.production.min.js -// @resource react/jsx-runtime https://unpkg.com/react@18.2.0/cjs/react-jsx-runtime.production.min.js -// @resource zustand https://unpkg.com/zustand@4.1.1/umd/index.production.js -// @resource zustand/vanilla https://unpkg.com/zustand@4.1.1/umd/vanilla.production.js -// @resource use-sync-external-store/shim/with-selector https://unpkg.com/use-sync-external-store@1.0.0/cjs/use-sync-external-store-with-selector.production.min.js -// @resource immer https://unpkg.com/immer@9.0.15/dist/immer.umd.production.min.js -// @resource react-shadow https://unpkg.com/react-shadow@19.0.3/react-shadow.js -// @resource prop-types https://unpkg.com/prop-types@15.8.1/prop-types.min.js -// @resource panzoom https://unpkg.com/panzoom@9.4.3/dist/panzoom.min.js -// @resource react-toastify https://unpkg.com/react-toastify@9.0.8/dist/react-toastify.js -// @resource clsx https://unpkg.com/clsx@1.2.1/dist/clsx.js -// @resource fflate https://unpkg.com/fflate@0.7.4/umd/index.js -// @resource dmzj_style https://userstyles.org/styles/chrome/119945.json -// @supportURL https://github.com/hymbz/ComicReadScript/issues -// @updateURL https://github.com/hymbz/ComicReadScript/raw/master/ComicRead.user.js -// @downloadURL https://github.com/hymbz/ComicReadScript/raw/master/ComicRead.user.js -// @grant GM_addElement -// @grant GM_getResourceText -// @grant GM_xmlhttpRequest -// @grant GM.getResourceText -// @grant GM.addStyle -// @grant GM.getValue -// @grant GM.setValue -// @grant GM.deleteValue -// @grant GM.registerMenuCommand -// @grant GM.unregisterMenuCommand -// @grant unsafeWindow -// ==/UserScript== -'use strict'; -// 为了尽量减少在无关页面浪费时间,将 components、helper 下的代码都转成文本存放在变量中 -// 只在需要使用时再通过和其他外部库一样的方式进行加载 -const helperCode = ` -Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } }); - -const require$$0 = require('react/jsx-runtime'); -const shadow = require('react-shadow'); -const reactToastify = require('react-toastify'); -const React = require('react'); -const require$$2 = require('clsx'); -const require$$2$1 = require('zustand'); -const require$$3 = require('immer'); -const require$$4 = require('panzoom'); -const fflate = require('fflate'); - -const _interopDefaultLegacy = e => e && typeof e === 'object' && 'default' in e ? e : { default: e }; - -function _interopNamespace(e) { - if (e && e.__esModule) return e; - const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } }); - if (e) { - for (const k in e) { - if (k !== 'default') { - const d = Object.getOwnPropertyDescriptor(e, k); - Object.defineProperty(n, k, d.get ? d : { - enumerable: true, - get: () => e[k] - }); - } - } - } - n.default = e; - return Object.freeze(n); -} - -const require$$0__default = /*#__PURE__*/_interopDefaultLegacy(require$$0); -const shadow__default = /*#__PURE__*/_interopDefaultLegacy(shadow); -const React__namespace = /*#__PURE__*/_interopNamespace(React); -const React__default = /*#__PURE__*/_interopDefaultLegacy(React); -const require$$2__default = /*#__PURE__*/_interopDefaultLegacy(require$$2); -const require$$2__default$1 = /*#__PURE__*/_interopDefaultLegacy(require$$2$1); -const require$$3__default = /*#__PURE__*/_interopDefaultLegacy(require$$3); -const require$$4__default = /*#__PURE__*/_interopDefaultLegacy(require$$4); -const fflate__default = /*#__PURE__*/_interopDefaultLegacy(fflate); - -const ToastStyle = ":root{--toastify-color-light:#fff;--toastify-color-dark:#121212;--toastify-color-info:#3498db;--toastify-color-success:#07bc0c;--toastify-color-warning:#f1c40f;--toastify-color-error:#e74c3c;--toastify-color-transparent:hsla(0,0%,100%,.7);--toastify-icon-color-info:var(--toastify-color-info);--toastify-icon-color-success:var(--toastify-color-success);--toastify-icon-color-warning:var(--toastify-color-warning);--toastify-icon-color-error:var(--toastify-color-error);--toastify-toast-width:320px;--toastify-toast-background:#fff;--toastify-toast-min-height:64px;--toastify-toast-max-height:800px;--toastify-font-family:sans-serif;--toastify-z-index:9999;--toastify-text-color-light:#757575;--toastify-text-color-dark:#fff;--toastify-text-color-info:#fff;--toastify-text-color-success:#fff;--toastify-text-color-warning:#fff;--toastify-text-color-error:#fff;--toastify-spinner-color:#616161;--toastify-spinner-color-empty-area:#e0e0e0;--toastify-color-progress-light:linear-gradient(90deg,#4cd964,#5ac8fa,#007aff,#34aadc,#5856d6,#ff2d55);--toastify-color-progress-dark:#bb86fc;--toastify-color-progress-info:var(--toastify-color-info);--toastify-color-progress-success:var(--toastify-color-success);--toastify-color-progress-warning:var(--toastify-color-warning);--toastify-color-progress-error:var(--toastify-color-error)}.Toastify__toast-container{z-index:var(--toastify-z-index);-webkit-transform:translateZ(var(--toastify-z-index));position:fixed;padding:4px;width:var(--toastify-toast-width);box-sizing:border-box;color:#fff}.Toastify__toast-container--top-left{top:1em;left:1em}.Toastify__toast-container--top-center{top:1em;left:50%;transform:translateX(-50%)}.Toastify__toast-container--top-right{top:1em;right:1em}.Toastify__toast-container--bottom-left{bottom:1em;left:1em}.Toastify__toast-container--bottom-center{bottom:1em;left:50%;transform:translateX(-50%)}.Toastify__toast-container--bottom-right{bottom:1em;right:1em}@media only screen and (max-width:480px){.Toastify__toast-container{width:100vw;padding:0;left:0;margin:0}.Toastify__toast-container--top-center,.Toastify__toast-container--top-left,.Toastify__toast-container--top-right{top:0;transform:translateX(0)}.Toastify__toast-container--bottom-center,.Toastify__toast-container--bottom-left,.Toastify__toast-container--bottom-right{bottom:0;transform:translateX(0)}.Toastify__toast-container--rtl{right:0;left:auto}}.Toastify__toast{position:relative;min-height:var(--toastify-toast-min-height);box-sizing:border-box;margin-bottom:1rem;padding:8px;border-radius:4px;box-shadow:0 1px 10px 0 rgba(0,0,0,.1),0 2px 15px 0 rgba(0,0,0,.05);display:-ms-flexbox;display:flex;-ms-flex-pack:justify;justify-content:space-between;max-height:var(--toastify-toast-max-height);overflow:hidden;font-family:var(--toastify-font-family);cursor:pointer;direction:ltr;z-index:0}.Toastify__toast--rtl{direction:rtl}.Toastify__toast-body{margin:auto 0;-ms-flex:1 1 auto;flex:1 1 auto;padding:6px;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.Toastify__toast-body>div:last-child{-ms-flex:1;flex:1}.Toastify__toast-icon{-webkit-margin-end:10px;margin-inline-end:10px;width:20px;-ms-flex-negative:0;flex-shrink:0;display:-ms-flexbox;display:flex}.Toastify--animate{animation-fill-mode:both;animation-duration:.7s}.Toastify--animate-icon{animation-fill-mode:both;animation-duration:.3s}@media only screen and (max-width:480px){.Toastify__toast{margin-bottom:0;border-radius:0}}.Toastify__toast-theme--dark{background:var(--toastify-color-dark);color:var(--toastify-text-color-dark)}.Toastify__toast-theme--colored.Toastify__toast--default,.Toastify__toast-theme--light{background:var(--toastify-color-light);color:var(--toastify-text-color-light)}.Toastify__toast-theme--colored.Toastify__toast--info{color:var(--toastify-text-color-info);background:var(--toastify-color-info)}.Toastify__toast-theme--colored.Toastify__toast--success{color:var(--toastify-text-color-success);background:var(--toastify-color-success)}.Toastify__toast-theme--colored.Toastify__toast--warning{color:var(--toastify-text-color-warning);background:var(--toastify-color-warning)}.Toastify__toast-theme--colored.Toastify__toast--error{color:var(--toastify-text-color-error);background:var(--toastify-color-error)}.Toastify__progress-bar-theme--light{background:var(--toastify-color-progress-light)}.Toastify__progress-bar-theme--dark{background:var(--toastify-color-progress-dark)}.Toastify__progress-bar--info{background:var(--toastify-color-progress-info)}.Toastify__progress-bar--success{background:var(--toastify-color-progress-success)}.Toastify__progress-bar--warning{background:var(--toastify-color-progress-warning)}.Toastify__progress-bar--error{background:var(--toastify-color-progress-error)}.Toastify__progress-bar-theme--colored.Toastify__progress-bar--error,.Toastify__progress-bar-theme--colored.Toastify__progress-bar--info,.Toastify__progress-bar-theme--colored.Toastify__progress-bar--success,.Toastify__progress-bar-theme--colored.Toastify__progress-bar--warning{background:var(--toastify-color-transparent)}.Toastify__close-button{color:#fff;background:transparent;outline:none;border:none;padding:0;cursor:pointer;opacity:.7;transition:.3s ease;-ms-flex-item-align:start;align-self:flex-start}.Toastify__close-button--light{color:#000;opacity:.3}.Toastify__close-button>svg{fill:currentColor;height:16px;width:14px}.Toastify__close-button:focus,.Toastify__close-button:hover{opacity:1}@keyframes Toastify__trackProgress{0%{transform:scaleX(1)}to{transform:scaleX(0)}}.Toastify__progress-bar{position:absolute;bottom:0;left:0;width:100%;height:5px;z-index:var(--toastify-z-index);opacity:.7;transform-origin:left}.Toastify__progress-bar--animated{animation:Toastify__trackProgress linear 1 forwards}.Toastify__progress-bar--controlled{transition:transform .2s}.Toastify__progress-bar--rtl{right:0;left:auto;transform-origin:right}.Toastify__spinner{width:20px;height:20px;box-sizing:border-box;border:2px solid;border-radius:100%;border-color:var(--toastify-spinner-color-empty-area);border-right-color:var(--toastify-spinner-color);animation:Toastify__spin .65s linear infinite}@keyframes Toastify__bounceInRight{0%,60%,75%,90%,to{animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;transform:translate3d(3000px,0,0)}60%{opacity:1;transform:translate3d(-25px,0,0)}75%{transform:translate3d(10px,0,0)}90%{transform:translate3d(-5px,0,0)}to{transform:none}}@keyframes Toastify__bounceOutRight{20%{opacity:1;transform:translate3d(-20px,0,0)}to{opacity:0;transform:translate3d(2000px,0,0)}}@keyframes Toastify__bounceInLeft{0%,60%,75%,90%,to{animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;transform:translate3d(-3000px,0,0)}60%{opacity:1;transform:translate3d(25px,0,0)}75%{transform:translate3d(-10px,0,0)}90%{transform:translate3d(5px,0,0)}to{transform:none}}@keyframes Toastify__bounceOutLeft{20%{opacity:1;transform:translate3d(20px,0,0)}to{opacity:0;transform:translate3d(-2000px,0,0)}}@keyframes Toastify__bounceInUp{0%,60%,75%,90%,to{animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;transform:translate3d(0,3000px,0)}60%{opacity:1;transform:translate3d(0,-20px,0)}75%{transform:translate3d(0,10px,0)}90%{transform:translate3d(0,-5px,0)}to{transform:translateZ(0)}}@keyframes Toastify__bounceOutUp{20%{transform:translate3d(0,-10px,0)}40%,45%{opacity:1;transform:translate3d(0,20px,0)}to{opacity:0;transform:translate3d(0,-2000px,0)}}@keyframes Toastify__bounceInDown{0%,60%,75%,90%,to{animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;transform:translate3d(0,-3000px,0)}60%{opacity:1;transform:translate3d(0,25px,0)}75%{transform:translate3d(0,-10px,0)}90%{transform:translate3d(0,5px,0)}to{transform:none}}@keyframes Toastify__bounceOutDown{20%{transform:translate3d(0,10px,0)}40%,45%{opacity:1;transform:translate3d(0,-20px,0)}to{opacity:0;transform:translate3d(0,2000px,0)}}.Toastify__bounce-enter--bottom-left,.Toastify__bounce-enter--top-left{animation-name:Toastify__bounceInLeft}.Toastify__bounce-enter--bottom-right,.Toastify__bounce-enter--top-right{animation-name:Toastify__bounceInRight}.Toastify__bounce-enter--top-center{animation-name:Toastify__bounceInDown}.Toastify__bounce-enter--bottom-center{animation-name:Toastify__bounceInUp}.Toastify__bounce-exit--bottom-left,.Toastify__bounce-exit--top-left{animation-name:Toastify__bounceOutLeft}.Toastify__bounce-exit--bottom-right,.Toastify__bounce-exit--top-right{animation-name:Toastify__bounceOutRight}.Toastify__bounce-exit--top-center{animation-name:Toastify__bounceOutUp}.Toastify__bounce-exit--bottom-center{animation-name:Toastify__bounceOutDown}@keyframes Toastify__zoomIn{0%{opacity:0;transform:scale3d(.3,.3,.3)}50%{opacity:1}}@keyframes Toastify__zoomOut{0%{opacity:1}50%{opacity:0;transform:scale3d(.3,.3,.3)}to{opacity:0}}.Toastify__zoom-enter{animation-name:Toastify__zoomIn}.Toastify__zoom-exit{animation-name:Toastify__zoomOut}@keyframes Toastify__flipIn{0%{transform:perspective(400px) rotateX(90deg);animation-timing-function:ease-in;opacity:0}40%{transform:perspective(400px) rotateX(-20deg);animation-timing-function:ease-in}60%{transform:perspective(400px) rotateX(10deg);opacity:1}80%{transform:perspective(400px) rotateX(-5deg)}to{transform:perspective(400px)}}@keyframes Toastify__flipOut{0%{transform:perspective(400px)}30%{transform:perspective(400px) rotateX(-20deg);opacity:1}to{transform:perspective(400px) rotateX(90deg);opacity:0}}.Toastify__flip-enter{animation-name:Toastify__flipIn}.Toastify__flip-exit{animation-name:Toastify__flipOut}@keyframes Toastify__slideInRight{0%{transform:translate3d(110%,0,0);visibility:visible}to{transform:translateZ(0)}}@keyframes Toastify__slideInLeft{0%{transform:translate3d(-110%,0,0);visibility:visible}to{transform:translateZ(0)}}@keyframes Toastify__slideInUp{0%{transform:translate3d(0,110%,0);visibility:visible}to{transform:translateZ(0)}}@keyframes Toastify__slideInDown{0%{transform:translate3d(0,-110%,0);visibility:visible}to{transform:translateZ(0)}}@keyframes Toastify__slideOutRight{0%{transform:translateZ(0)}to{visibility:hidden;transform:translate3d(110%,0,0)}}@keyframes Toastify__slideOutLeft{0%{transform:translateZ(0)}to{visibility:hidden;transform:translate3d(-110%,0,0)}}@keyframes Toastify__slideOutDown{0%{transform:translateZ(0)}to{visibility:hidden;transform:translate3d(0,500px,0)}}@keyframes Toastify__slideOutUp{0%{transform:translateZ(0)}to{visibility:hidden;transform:translate3d(0,-500px,0)}}.Toastify__slide-enter--bottom-left,.Toastify__slide-enter--top-left{animation-name:Toastify__slideInLeft}.Toastify__slide-enter--bottom-right,.Toastify__slide-enter--top-right{animation-name:Toastify__slideInRight}.Toastify__slide-enter--top-center{animation-name:Toastify__slideInDown}.Toastify__slide-enter--bottom-center{animation-name:Toastify__slideInUp}.Toastify__slide-exit--bottom-left,.Toastify__slide-exit--top-left{animation-name:Toastify__slideOutLeft}.Toastify__slide-exit--bottom-right,.Toastify__slide-exit--top-right{animation-name:Toastify__slideOutRight}.Toastify__slide-exit--top-center{animation-name:Toastify__slideOutUp}.Toastify__slide-exit--bottom-center{animation-name:Toastify__slideOutDown}@keyframes Toastify__spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}"; - -let selfToast; -const useToast = () => { - if (selfToast) - return selfToast; - const [root] = useComponentsRoot('toast'); - const _selfToast = (text, options) => { - root.render(require$$0.jsxs(shadow__default.default.div, { style: { fontSize: 16 }, children: [require$$0.jsx(reactToastify.ToastContainer, { autoClose: 1000 * 3, style: { - // 进度条颜色 - '--toastify-color-progress-light': '#7A909A', - // 背景色 - '--toastify-color-light': 'white', - } }), require$$0.jsxs("style", { type: "text/css", children: [ToastStyle.replace(':root', '.Toastify'), \` - h2 { - font-size: 1.1em; - margin: 0; - margin-bottom: 1em; - } - .md { - text-align: left; - } - .md ul, .md h2 { - margin:0; - margin-bottom: .5em; - font-size: 1em; - } - \`] })] })); - reactToastify.toast(text, { ...options }); - }; - _selfToast.info = (text, options) => _selfToast(text, { ...options, type: 'info' }); - _selfToast.error = (text, options) => _selfToast(text, { ...options, type: 'error' }); - _selfToast.warn = (text, options) => _selfToast(text, { ...options, type: 'warning' }); - _selfToast.success = (text, options) => _selfToast(text, { ...options, type: 'success' }); - selfToast = _selfToast; - return selfToast; -}; - -// eslint-disable-next-line import/no-cycle -const sleep = (ms) => new Promise((resolve) => { - window.setTimeout(resolve, ms); -}); -/** - * 对 document.querySelector 的封装 - * 将默认返回类型改为 HTMLElement - */ -const querySelector = (selector) => document.querySelector(selector); -/** - * 对 document.querySelector 的封装 - * 将默认返回类型改为 HTMLElement - */ -const querySelectorAll = (selector) => [...document.querySelectorAll(selector)]; -/** - * 添加元素 - * - * @param node 被添加元素 - * @param textnode 添加元素 - * @param referenceNode 参考元素,添加元素将插在参考元素前 - */ -const insertNode = (node, textnode, referenceNode = null) => { - const temp = document.createElement('div'); - temp.innerHTML = textnode; - const frag = document.createDocumentFragment(); - while (temp.firstChild) - frag.appendChild(temp.firstChild); - node.insertBefore(frag, referenceNode); -}; -/** 创建组件用的 ReactDOM Root */ -const useComponentsRoot = (id) => { - // 需要使用动态导入以避免在支持站点外的页面上加载 React - // eslint-disable-next-line @typescript-eslint/consistent-type-imports - const ReactDOM = require('react-dom'); - const dom = document.getElementById(id) ?? - (() => { - const _dom = document.createElement('div'); - _dom.id = id; - document.body.appendChild(_dom); - return _dom; - })(); - return [ReactDOM.createRoot(dom), dom]; -}; -/** 返回 Dom 的点击函数,如果找不到 Dom 则返回 null */ -const querySelectorClick = (selector) => { - const dom = querySelector(selector); - if (!dom) - return null; - return () => { - dom.click(); - }; -}; -/** 判断两个列表中包含的值是否相同 */ -const isEqualArray = (a, b) => a.length === b.length && !!a.filter((t) => !b.includes(t)); -/** 将对象转为 URLParams 类型的字符串 */ -const dataToParams = (data) => Object.entries(data) - .map(([key, val]) => \`\${key}=\${val}\`) - .join('&'); -/** 将 blob 数据作为文件保存至本地 */ -const saveAs = (blob, name = 'download') => { - const a = document.createElementNS('http://www.w3.org/1999/xhtml', 'a'); - a.download = name; - a.rel = 'noopener'; - a.href = URL.createObjectURL(blob); - setTimeout(() => a.dispatchEvent(new MouseEvent('click'))); -}; -/** 监听键盘事件 */ -const linstenKeyup = (handler) => window.addEventListener('keyup', (e) => { - // 跳过输入框的键盘事件 - switch (e.target.tagName) { - case 'INPUT': - case 'TEXTAREA': - return; - } - handler(e); -}); -/** 滚动页面到指定元素的所在位置 */ -const scrollIntoView = (selector) => { - querySelector(selector)?.scrollIntoView(); -}; -/** - * 限制 Promise 并发 - * - * @param limit 限制数 - * @param fnList 返回 Promise 的函数 - * @param callBack 成功执行一个 Promise 后调用,主要用于显示进度 - * @returns 所有 Promise 的返回值 - */ -const plimit = async (limit, fnList, callBack) => { - const totalNum = fnList.length; - const resList = []; - const execPool = new Set(); - const taskList = fnList.map((fn, i) => { - let p; - return () => { - p = (async () => { - resList[i] = await fn(); - execPool.delete(p); - callBack?.(resList); - })(); - execPool.add(p); - }; - }); - while (resList.length !== totalNum) { - while (taskList.length && execPool.size < limit) { - taskList.shift()(); - } - // eslint-disable-next-line no-await-in-loop - await Promise.race(execPool); - } - return resList; -}; -// 将 xmlHttpRequest 包装为 Promise -const xmlHttpRequest = (details) => new Promise((resolve, reject) => { - GM_xmlhttpRequest({ - ...details, - onload: resolve, - onerror: reject, - ontimeout: reject, - }); -}); -/** 发起请求 */ -const request = async (url, details, errorNum = 0) => { - const errorText = details?.errorText ?? '漫画加载出错'; - try { - const res = await xmlHttpRequest({ - method: 'GET', - url, - headers: { Referer: window.location.href }, - ...details, - }); - if (res.status !== 200) - throw new Error(errorText); - return res; - } - catch (error) { - if (errorNum > 3) { - if (errorText) - useToast().error(errorText); - throw new Error(errorText); - } - console.error(errorText, error); - await sleep(1000); - return request(url, details, errorNum + 1); - } -}; - -var _path$9; -function _extends$9() { _extends$9 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$9.apply(this, arguments); } -const SvgFileDownload = props => /*#__PURE__*/React__namespace.createElement("svg", _extends$9({ - xmlns: "http://www.w3.org/2000/svg", - width: "1em", - height: "1em", - viewBox: "0 0 24 24", - role: "img", - stroke: "currentColor", - fill: "currentColor", - strokeWidth: "0" -}, props), _path$9 || (_path$9 = /*#__PURE__*/React__namespace.createElement("path", { - d: "M16.59 9H15V4c0-.55-.45-1-1-1h-4c-.55 0-1 .45-1 1v5H7.41c-.89 0-1.34 1.08-.71 1.71l4.59 4.59c.39.39 1.02.39 1.41 0l4.59-4.59c.63-.63.19-1.71-.7-1.71zM5 19c0 .55.45 1 1 1h12c.55 0 1-.45 1-1s-.45-1-1-1H6c-.55 0-1 .45-1 1z" -}))); - -var _path$8; -function _extends$8() { _extends$8 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$8.apply(this, arguments); } -const SvgClose = props => /*#__PURE__*/React__namespace.createElement("svg", _extends$8({ - xmlns: "http://www.w3.org/2000/svg", - width: "1em", - height: "1em", - viewBox: "0 0 24 24", - role: "img", - stroke: "currentColor", - fill: "currentColor", - strokeWidth: "0" -}, props), _path$8 || (_path$8 = /*#__PURE__*/React__namespace.createElement("path", { - d: "M18.3 5.71a.996.996 0 0 0-1.41 0L12 10.59 7.11 5.7A.996.996 0 1 0 5.7 7.11L10.59 12 5.7 16.89a.996.996 0 1 0 1.41 1.41L12 13.41l4.89 4.89a.996.996 0 1 0 1.41-1.41L13.41 12l4.89-4.89c.38-.38.38-1.02 0-1.4z" -}))); - -var IconButton = {exports: {}}; - -(function (module, exports) { - Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } }); - const main = () => { - const jsxRuntime = require$$0__default.default; - const react = React__default.default; - const clsx = require$$2__default.default; - const _interopDefaultLegacy = e => e && typeof e === 'object' && 'default' in e ? e : { default: e }; - const clsx__default = /*#__PURE__*/ _interopDefaultLegacy(clsx); - const classes = { "iconButtonItem": "index-module_iconButtonItem__jb7BZ", "iconButton": "index-module_iconButton__-XHmw", "enabled": "index-module_enabled__NKlE9", "iconButtonPopper": "index-module_iconButtonPopper__vhloV", "hidden": "index-module_hidden__jOPaw" }; - /** - * 图标按钮 - * - * @param param param - */ - const IconButton = react.memo(({ children, tip, hidden, enabled, ref, showTip, placement = 'right', popper, popperClassName, onClick, }) => { - const buttonRef = react.useRef(ref?.current ?? null); - const handleClick = (e) => { - // 在每次点击后取消焦点 - buttonRef.current?.blur(); - return onClick?.(e); - }; - return (jsxRuntime.jsxs("div", { className: classes.iconButtonItem, "data-show": showTip, children: [jsxRuntime.jsx("button", { ref: buttonRef, "aria-label": tip, type: "button", className: clsx__default.default(classes.iconButton, { [classes.hidden]: hidden }, enabled && classes.enabled), onClick: handleClick, children: children }), popper || tip ? (jsxRuntime.jsx("div", { className: clsx__default.default(classes.iconButtonPopper, popperClassName), "data-placement": placement, children: popper || tip })) : null] })); - }); - exports.IconButton = IconButton; - }; - const selfModule = module.exports; - module.exports = new Proxy(selfModule, { - get(_, prop) { - if (selfModule[prop] === undefined) - main(); - return selfModule[prop]; - }, - apply(_, __, args) { - if (selfModule[prop] === undefined) - main(); - return selfModule[prop](...args); - }, - construct(_, args) { - if (selfModule[prop] === undefined) - main(); - return new selfModule[prop](...args); - }, - }); -}(IconButton, IconButton.exports)); - -var Manga = {exports: {}}; - -(function (module, exports) { - Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } }); - const main = () => { - const jsxRuntime = require$$0__default.default; - const React = React__default.default; - const create = require$$2__default$1.default; - const immer$1 = require$$3__default.default; - const createPanZoom = require$$4__default.default; - const clsx = require$$2__default.default; - const _interopDefaultLegacy = e => e && typeof e === 'object' && 'default' in e ? e : { default: e }; - function _interopNamespace(e) { - if (e && e.__esModule) - return e; - const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } }); - if (e) { - for (const k in e) { - if (k !== 'default') { - const d = Object.getOwnPropertyDescriptor(e, k); - Object.defineProperty(n, k, d.get ? d : { - enumerable: true, - get: () => e[k] - }); - } - } - } - n.default = e; - return Object.freeze(n); - } - const React__namespace = /*#__PURE__*/ _interopNamespace(React); - const create__default = /*#__PURE__*/ _interopDefaultLegacy(create); - const createPanZoom__default = /*#__PURE__*/ _interopDefaultLegacy(createPanZoom); - const clsx__default = /*#__PURE__*/ _interopDefaultLegacy(clsx); - /* eslint-disable no-undefined,no-param-reassign,no-shadow */ - /** - * Throttle execution of a function. Especially useful for rate limiting - * execution of handlers on events like resize and scroll. - * - * @param {number} delay - A zero-or-greater delay in milliseconds. For event callbacks, values around 100 or 250 (or even higher) - * are most useful. - * @param {Function} callback - A function to be executed after delay milliseconds. The \`this\` context and all arguments are passed through, - * as-is, to \`callback\` when the throttled-function is executed. - * @param {object} [options] - An object to configure options. - * @param {boolean} [options.noTrailing] - Optional, defaults to false. If noTrailing is true, callback will only execute every \`delay\` milliseconds - * while the throttled-function is being called. If noTrailing is false or unspecified, callback will be executed - * one final time after the last throttled-function call. (After the throttled-function has not been called for - * \`delay\` milliseconds, the internal counter is reset). - * @param {boolean} [options.noLeading] - Optional, defaults to false. If noLeading is false, the first throttled-function call will execute callback - * immediately. If noLeading is true, the first the callback execution will be skipped. It should be noted that - * callback will never executed if both noLeading = true and noTrailing = true. - * @param {boolean} [options.debounceMode] - If \`debounceMode\` is true (at begin), schedule \`clear\` to execute after \`delay\` ms. If \`debounceMode\` is - * false (at end), schedule \`callback\` to execute after \`delay\` ms. - * - * @returns {Function} A new, throttled, function. - */ - function throttle(delay, callback, options) { - var _ref = options || {}, _ref$noTrailing = _ref.noTrailing, noTrailing = _ref$noTrailing === void 0 ? false : _ref$noTrailing, _ref$noLeading = _ref.noLeading, noLeading = _ref$noLeading === void 0 ? false : _ref$noLeading, _ref$debounceMode = _ref.debounceMode, debounceMode = _ref$debounceMode === void 0 ? undefined : _ref$debounceMode; - /* - * After wrapper has stopped being called, this timeout ensures that - * \`callback\` is executed at the proper times in \`throttle\` and \`end\` - * debounce modes. - */ - var timeoutID; - var cancelled = false; // Keep track of the last time \`callback\` was executed. - var lastExec = 0; // Function to clear existing timeout - function clearExistingTimeout() { - if (timeoutID) { - clearTimeout(timeoutID); - } - } // Function to cancel next exec - function cancel(options) { - var _ref2 = options || {}, _ref2$upcomingOnly = _ref2.upcomingOnly, upcomingOnly = _ref2$upcomingOnly === void 0 ? false : _ref2$upcomingOnly; - clearExistingTimeout(); - cancelled = !upcomingOnly; - } - /* - * The \`wrapper\` function encapsulates all of the throttling / debouncing - * functionality and when executed will limit the rate at which \`callback\` - * is executed. - */ - function wrapper() { - for (var _len = arguments.length, arguments_ = new Array(_len), _key = 0; _key < _len; _key++) { - arguments_[_key] = arguments[_key]; - } - var self = this; - var elapsed = Date.now() - lastExec; - if (cancelled) { - return; - } // Execute \`callback\` and update the \`lastExec\` timestamp. - function exec() { - lastExec = Date.now(); - callback.apply(self, arguments_); - } - /* - * If \`debounceMode\` is true (at begin) this is used to clear the flag - * to allow future \`callback\` executions. - */ - function clear() { - timeoutID = undefined; - } - if (!noLeading && debounceMode && !timeoutID) { - /* - * Since \`wrapper\` is being called for the first time and - * \`debounceMode\` is true (at begin), execute \`callback\` - * and noLeading != true. - */ - exec(); - } - clearExistingTimeout(); - if (debounceMode === undefined && elapsed > delay) { - if (noLeading) { - /* - * In throttle mode with noLeading, if \`delay\` time has - * been exceeded, update \`lastExec\` and schedule \`callback\` - * to execute after \`delay\` ms. - */ - lastExec = Date.now(); - if (!noTrailing) { - timeoutID = setTimeout(debounceMode ? clear : exec, delay); - } - } - else { - /* - * In throttle mode without noLeading, if \`delay\` time has been exceeded, execute - * \`callback\`. - */ - exec(); - } - } - else if (noTrailing !== true) { - /* - * In trailing throttle mode, since \`delay\` time has not been - * exceeded, schedule \`callback\` to execute \`delay\` ms after most - * recent execution. - * - * If \`debounceMode\` is true (at begin), schedule \`clear\` to execute - * after \`delay\` ms. - * - * If \`debounceMode\` is false (at end), schedule \`callback\` to - * execute after \`delay\` ms. - */ - timeoutID = setTimeout(debounceMode ? clear : exec, debounceMode === undefined ? delay - elapsed : delay); - } - } - wrapper.cancel = cancel; // Return the wrapper function. - return wrapper; - } - /* eslint-disable no-undefined */ - /** - * Debounce execution of a function. Debouncing, unlike throttling, - * guarantees that a function is only executed a single time, either at the - * very beginning of a series of calls, or at the very end. - * - * @param {number} delay - A zero-or-greater delay in milliseconds. For event callbacks, values around 100 or 250 (or even higher) are most useful. - * @param {Function} callback - A function to be executed after delay milliseconds. The \`this\` context and all arguments are passed through, as-is, - * to \`callback\` when the debounced-function is executed. - * @param {object} [options] - An object to configure options. - * @param {boolean} [options.atBegin] - Optional, defaults to false. If atBegin is false or unspecified, callback will only be executed \`delay\` milliseconds - * after the last debounced-function call. If atBegin is true, callback will be executed only at the first debounced-function call. - * (After the throttled-function has not been called for \`delay\` milliseconds, the internal counter is reset). - * - * @returns {Function} A new, debounced function. - */ - function debounce(delay, callback, options) { - var _ref = options || {}, _ref$atBegin = _ref.atBegin, atBegin = _ref$atBegin === void 0 ? false : _ref$atBegin; - return throttle(delay, callback, { - debounceMode: atBegin !== false - }); - } - const immerImpl = (initializer) => (set, get, store) => { - store.setState = (updater, replace, ...a) => { - const nextState = typeof updater === "function" ? immer$1.produce(updater) : updater; - return set(nextState, replace, ...a); - }; - return initializer(store.setState, get, store); - }; - const immer = immerImpl; - const subscribeWithSelectorImpl = (fn) => (set, get, api) => { - const origSubscribe = api.subscribe; - api.subscribe = (selector, optListener, options) => { - let listener = selector; - if (optListener) { - const equalityFn = (options == null ? void 0 : options.equalityFn) || Object.is; - let currentSlice = selector(api.getState()); - listener = (state) => { - const nextSlice = selector(state); - if (!equalityFn(currentSlice, nextSlice)) { - const previousSlice = currentSlice; - optListener(currentSlice = nextSlice, previousSlice); - } - }; - if (options == null ? void 0 : options.fireImmediately) { - optListener(currentSlice, currentSlice); - } - } - return origSubscribe(listener); - }; - const initialState = fn(set, get, api); - return initialState; - }; - const subscribeWithSelector = subscribeWithSelectorImpl; - const optionSlice = () => ({ - option: { - dir: 'rtl', - scrollbar: { - enabled: true, - autoHidden: false, - showProgress: true, - }, - onePageMode: false, - scrollMode: false, - clickPage: { - enabled: 'ontouchstart' in document.documentElement, - overturn: false, - }, - disableZoom: false, - // 判断用户系统环境是否要求开启暗色模式 - darkMode: window.matchMedia('(prefers-color-scheme: dark)').matches, - autoLoadOtherImg: 5, - flipToNext: true, - }, - showTouchArea: false, - }); - /** - * 根据图片比例和填充页设置对漫画图片进行排列 - */ - const handleComicData = ({ comicImgList, fillEffect, }) => { - const pageList = []; - let imgCache = null; - for (let i = 0; i < comicImgList.length; i += 1) { - const img = comicImgList[i]; - if (fillEffect.get(i - 1)) { - if (imgCache !== null) - throw new Error('imgCache 被覆盖'); - imgCache = -1; - } - if (img.type !== 'long' && img.type !== 'wide') { - if (imgCache !== null) { - pageList.push([imgCache, i]); - imgCache = null; - } - else { - imgCache = i; - } - } - else { - if (imgCache !== null) { - if (imgCache !== -1) - pageList.push([-1, imgCache]); - imgCache = null; - } - if (fillEffect.get(i) === undefined && img.loadType !== 'loading') - fillEffect.set(i, false); - pageList.push([i]); - } - } - if (imgCache !== null && imgCache !== -1) { - pageList.push([imgCache, -1]); - imgCache = null; - } - return pageList; - }; - /** 加载状态的中文描述 */ - const loadTypeMap = { - error: '加载出错', - loading: '正在加载', - wait: '等待加载', - loaded: '', - }; - /** - * 预加载指定页数的图片,并取消其他预加载的图片 - * - * @param state state - * @param startIndex 起始 page index - * @param endIndex 结束 page index - * @param loadNum 加载图片的数量 - * @returns 返回指定范围内的图片在执行前是否还有未加载完的 - */ - const loadImg = (state, startIndex, endIndex = startIndex, loadNum = NaN) => { - let editNum = 0; - state.pageList - .slice(startIndex, endIndex) - .flat() - .some((index) => { - if (index === -1) - return false; - const img = state.imgList[index]; - if (img.loadType !== 'loaded') { - img.loadType = 'loading'; - editNum += 1; - } - return editNum >= loadNum; - }); - const edited = editNum > 0; - if (edited) - state.scrollbar.updateTipText(state); - return edited; - }; - const imageSlice = (set, get) => { - const _updatePageData = (state) => { - if (state.option.onePageMode || state.option.scrollMode) - state.pageList = state.imgList.map((_, i) => [i]); - else - state.pageList = handleComicData({ - comicImgList: state.imgList, - fillEffect: state.fillEffect, - }); - state.scrollbar.updateDrag(state); - state.img.updateImgLoadType(); - }; - return { - imgList: [], - fillEffect: new Map([[-1, true]]), - pageList: [], - activeImgIndex: 0, - activePageIndex: 0, - nowFillIndex: -1, - onLoading: undefined, - img: { - 单页比例: 0, - 横幅比例: 0, - 条漫比例: 0, - updatePageData: Object.assign(debounce(100, () => set(_updatePageData)), { sync: _updatePageData }), - updateImgType: (draftImg) => { - const { img: { 单页比例, 横幅比例, 条漫比例, updatePageData }, } = get(); - const { width, height } = draftImg; - if (width && height) { - const imgRatio = width / height; - if (imgRatio <= 单页比例) { - if (imgRatio < 条漫比例) - draftImg.type = 'vertical'; - } - else { - draftImg.type = imgRatio > 横幅比例 ? 'long' : 'wide'; - } - } - set(updatePageData); - }, - updatePageRatio: (state, width, height) => { - state.img.单页比例 = Math.min(width / 2 / height, 1); - state.img.横幅比例 = width / height; - state.img.条漫比例 = state.img.单页比例 / 2; - state.imgList.forEach(state.img.updateImgType); - state.scrollbar.updateDrag(state); - }, - switchFillEffect: () => { - set((state) => { - state.fillEffect.set(state.nowFillIndex, !state.fillEffect.get(state.nowFillIndex)); - state.img.updatePageData(); - }); - }, - updateImgLoadType: debounce(100, () => { - set((state) => { - const { imgList, activePageIndex } = state; - // 先将所有加载中的图片状态改为暂停 - imgList.forEach(({ loadType }, i) => { - if (loadType === 'loading' || loadType === 'error') - imgList[i].loadType = 'wait'; - }); - if ( - // 如果当前显示页还没有加载完,则优先加载 - loadImg(state, activePageIndex, activePageIndex + 1) || - // 之后加载后俩页 - loadImg(state, activePageIndex + 1, activePageIndex + 3) || - // 最后加载前一页 - (activePageIndex >= 1 && - loadImg(state, activePageIndex - 1, activePageIndex))) - return; - // 确认没有图片在加载后,在空闲时间自动加载其余图片 - if (!state.option.autoLoadOtherImg && - imgList.some((img) => img.loadType === 'loading')) - return; - // 优先加载当前页后面的图片 - if (loadImg(state, activePageIndex + 1, imgList.length, state.option.autoLoadOtherImg)) - return; - loadImg(state, 0, imgList.length, state.option.autoLoadOtherImg); - }); - }), - }, - turnPage: (dir) => { - const { pageList, endPageType, activePageIndex } = get(); - set((state) => { - if (dir === 'prev') { - switch (endPageType) { - case 'start': - if (!state.scrollLock && state.option.flipToNext) - state.onPrev?.(); - return; - case 'end': - state.endPageType = undefined; - return; - default: - // 弹出卷首结束页 - if (activePageIndex === 0) { - // 没有 onPrev 时不弹出 - if (!state.onPrev || !state.option.flipToNext) - return; - state.endPageType = 'start'; - state.scrollLock = true; - window.setTimeout(() => { - set((draftState) => { - draftState.scrollLock = false; - }); - }, 500); - return; - } - if (!state.option.scrollMode) - state.activePageIndex -= 1; - } - } - else { - switch (endPageType) { - case 'end': - if (state.scrollLock) - return; - if (state.onNext && state.option.flipToNext) { - state.onNext(); - return; - } - if (state.onExit) { - state.onExit(true); - state.activePageIndex = 0; - state.endPageType = undefined; - } - return; - case 'start': - state.endPageType = undefined; - return; - default: - // 弹出卷尾结束页 - if (activePageIndex === pageList.length - 1) { - state.endPageType = 'end'; - state.scrollLock = true; - window.setTimeout(() => { - set((draftState) => { - draftState.scrollLock = false; - }); - }, 200); - return; - } - if (!state.option.scrollMode) - state.activePageIndex += 1; - } - } - }); - }, - }; - }; - const imageCallback = (useStore) => { - // 页数发生变动时 - useStore.subscribe((state) => state.activePageIndex, () => { - useStore.setState((state) => { - // 重新计算 activeImgIndex - state.activeImgIndex = - state.pageList[state.activePageIndex].find((i) => i !== -1) ?? 0; - // 找到当前所属的 fillEffect - let nowFillIndex = state.activeImgIndex; - while (!state.fillEffect.has(nowFillIndex) && (nowFillIndex -= 1)) - ; - state.nowFillIndex = nowFillIndex; - state.img.updateImgLoadType(); - if (state.endPageType) - state.endPageType = undefined; - }); - }); - }; - const externalLibSlice = (set, get) => ({ - panzoom: undefined, - initPanzoom: () => { - const { mangaFlowRef } = get(); - set((state) => { - // 销毁之前可能创建过的实例 - state.panzoom?.dispose(); - const panzoom = createPanZoom__default.default(mangaFlowRef.current, { - // 边界限制 - bounds: true, - boundsPadding: 1, - // 禁止缩小 - minZoom: 1, - // 禁用默认的双击缩放 - zoomDoubleClickSpeed: 1, - // 忽略键盘事件 - filterKey: () => true, - beforeWheel(e) { - const { scale } = panzoom.getTransform(); - // 图片不处于放大状态时,必须按下 Alt 键才能通过滚轮缩放 - if (e.altKey && scale === 1) - return false; - // 图片处于放大状态时,可以直接通过滚轮缩放 - if (scale !== 1) - return false; - return true; - }, - beforeMouseDown(e) { - // 按下「alt 键」或「处于放大状态」时才允许拖动 - return !(e.altKey || panzoom.getTransform().scale !== 1); - }, - onTouch() { - // 未进行缩放时不捕捉 touch 事件 - const { scale } = panzoom.getTransform(); - return scale !== 1; - }, - }); - panzoom.on('transform', () => { - if (panzoom.getTransform().scale === 1) { - const { scrollLock } = get(); - // 防止在放大模式下通过滚轮缩小至原尺寸后立刻跳转至下一页 - if (scrollLock) - window.setTimeout(() => { - set((draftState) => { - draftState.scrollLock = false; - }); - }, 500); - } - else { - const { scrollLock } = get(); - if (!scrollLock) - set((draftState) => { - draftState.scrollLock = true; - }); - } - }); - state.panzoom = panzoom; - }); - }, - }); - const operateSlice = (set, get) => ({ - scrollLock: false, - handleScroll: (e) => { - e.stopPropagation(); - const { option: { scrollMode }, turnPage, scrollLock, endPageType, } = get(); - if (e.altKey || (!endPageType && scrollLock)) - return; - if (scrollMode && !endPageType) { - set((state) => { - if (state.scrollbar.dragTop === 0 && e.deltaY <= 0) { - state.endPageType = 'start'; - state.scrollLock = true; - window.setTimeout(() => { - set((draftState) => { - draftState.scrollLock = false; - }); - }, 500); - } - else if (state.scrollbar.dragHeight + state.scrollbar.dragTop === 1) { - state.endPageType = 'end'; - state.scrollLock = true; - window.setTimeout(() => { - set((draftState) => { - draftState.scrollLock = false; - }); - }, 500); - } - }); - return; - } - if (e.deltaY > 0) - turnPage('next'); - else - turnPage('prev'); - }, - handleKeyUp: (e) => { - e.stopPropagation(); - const { turnPage, img: { switchFillEffect }, option: { dir, scrollMode }, onExit, pageList, endPageType, } = get(); - if (scrollMode && !endPageType) - return; - let nextPage = null; - switch (e.key) { - case 'PageUp': - case 'ArrowUp': - case '.': - case 'w': - nextPage = false; - break; - case ' ': - case 'PageDown': - case 'ArrowDown': - case ',': - case 's': - nextPage = true; - break; - case 'ArrowRight': - case 'd': - nextPage = dir !== 'rtl'; - break; - case 'ArrowLeft': - case 'a': - nextPage = dir === 'rtl'; - break; - case '/': - case 'm': - case 'z': - switchFillEffect(); - break; - case 'Home': - set((state) => { - state.activePageIndex = 0; - }); - break; - case 'End': - set((state) => { - state.activePageIndex = pageList.length - 1; - }); - break; - case 'Escape': - onExit?.(); - break; - } - if (nextPage === null) - return; - turnPage(nextPage ? 'next' : 'prev'); - }, - }); - function shallow(objA, objB) { - if (Object.is(objA, objB)) { - return true; - } - if (typeof objA !== "object" || objA === null || typeof objB !== "object" || objB === null) { - return false; - } - const keysA = Object.keys(objA); - if (keysA.length !== Object.keys(objB).length) { - return false; - } - for (let i = 0; i < keysA.length; i++) { - if (!Object.prototype.hasOwnProperty.call(objB, keysA[i]) || !Object.is(objA[keysA[i]], objB[keysA[i]])) { - return false; - } - } - return true; - } - /** 开始拖拽时的 dragTop 值 */ - let startTop = 0; - /** - * 获取指定 page 中的图片 index,并在后面加上加载状态 - */ - const getPageIndexText = (state, pageIndex) => { - const pageIndexText = state.pageList[pageIndex].map((index) => { - if (index === -1) - return '填充页'; - const img = state.imgList[index]; - if (img.loadType === 'loaded') - return \`\${index}\`; - // 如果图片未加载完毕则在其 index 后增加显示当前加载状态 - return \`\${index} (\${loadTypeMap[img.loadType]})\`; - }); - if (state.option.dir === 'rtl') - pageIndexText.reverse(); - return pageIndexText; - }; - const scrollbarSlice = (set, get) => ({ - scrollbar: { - tipText: '', - dragHeight: 0, - dragTop: 0, - updateTipText: (state) => { - state.scrollbar.tipText = (() => { - if (!state.pageList.length) - return ''; - if (!state.option.scrollMode) - return getPageIndexText(state, state.activePageIndex).join(' | '); - const { pageList, scrollbar: { dragHeight, dragTop }, } = state; - const pageIndex = pageList - .slice(Math.floor(dragTop * pageList.length), Math.floor((dragTop + dragHeight) * pageList.length)) - .flat() - .map((index) => getPageIndexText(state, index)); - return pageIndex.join('\\n'); - })(); - }, - updateDrag: (state) => { - if (!state.option.scrollMode) { - state.scrollbar.dragHeight = 0; - state.scrollbar.dragTop = 0; - return; - } - /** 能显示出漫画的高度 */ - const windowHeight = state.rootRef.current?.offsetHeight; - /** 漫画的总高度 */ - const contentHeight = state.mangaFlowRef.current?.scrollHeight; - state.scrollbar.dragHeight = - !windowHeight || !contentHeight ? 0 : windowHeight / contentHeight; - }, - handleMangaFlowScroll: () => { - set((state) => { - if (!state.option.scrollMode) - return; - const mangaFlowDom = state.mangaFlowRef.current; - /** 漫画的总高度 */ - const contentHeight = mangaFlowDom?.scrollHeight; - state.scrollbar.dragTop = - !mangaFlowDom || !contentHeight - ? 0 - : mangaFlowDom.scrollTop / contentHeight; - state.activePageIndex = Math.floor(state.scrollbar.dragTop * state.pageList.length); - state.scrollbar.updateDrag(state); - }); - }, - // 使在滚动条上的滚轮可以触发滚动 - handleWheel: (e) => { - const { mangaFlowRef, rootRef } = get(); - /** 能显示出漫画的高度 */ - const windowHeight = rootRef.current?.offsetHeight; - if (!windowHeight) - return; - /** 滚动条高度 */ - const scrollbarHeight = e.target.offsetHeight; - // 使用 scrollBy 会导致和原生滚动效果不同,少了平滑滚动,但初次之外找不到其他办法了 - mangaFlowRef.current?.scrollBy({ - top: (e.nativeEvent.deltaY / scrollbarHeight) * windowHeight, - }); - }, - dragOption: { - handleDrag: ({ type, xy: [, y], initial: [, iy] }, e) => { - // 跳过拖拽结束事件(单击时会同时触发开始和结束,就用开始事件来完成单击的效果 - if (type === 'end') - return; - // 跳过没必要处理的情况 - if (type === 'dragging' && y === iy) - return; - const { activePageIndex, mangaFlowRef, pageList, option: { scrollMode }, scrollbar: { dragHeight }, } = get(); - if (!mangaFlowRef.current) - return; - /** 滚动条高度 */ - const scrollbarHeight = e.target.offsetHeight; - /** 点击位置在滚动条上的位置比率 */ - const clickTop = y / scrollbarHeight; - let top = clickTop; - if (scrollMode) { - /** 漫画的总高度 */ - const contentHeight = mangaFlowRef.current.scrollHeight; - if (type === 'dragging') { - /** 在滚动条上的移动比率 */ - const dy = (y - iy) / scrollbarHeight; - top = startTop + dy; - // 处理超出范围的情况 - if (top < 0) - top = 0; - else if (top > 1) - top = 1; - mangaFlowRef.current.scrollTo({ top: top * contentHeight }); - } - else { - // 确保滚动条的中心会在点击位置 - top -= dragHeight / 2; - startTop = top; - mangaFlowRef.current.scrollTo({ - top: top * contentHeight, - behavior: 'smooth', - }); - } - } - else { - let newPageIndex = Math.floor(top * pageList.length); - // 处理超出范围的情况 - if (newPageIndex < 0) - newPageIndex = 0; - else if (newPageIndex >= pageList.length) - newPageIndex = pageList.length - 1; - if (newPageIndex !== activePageIndex) - set((state) => { - state.activePageIndex = newPageIndex; - }); - } - }, - }, - }, - }); - const scrollbarCallback = (useStore) => { - // 更新滚动条提示文本 - useStore.subscribe(({ activePageIndex, pageList, scrollbar: { dragHeight, dragTop }, option: { scrollMode, dir }, }) => [activePageIndex, pageList, dragHeight, dragTop, scrollMode, dir], () => { - useStore.setState((state) => { - state.scrollbar.updateTipText(state); - }); - }, { equalityFn: shallow }); - }; - const otherSlice = () => ({ - showToolbar: false, - showScrollbar: false, - showEndPage: false, - endPageType: undefined, - editButtonList: (list) => list, - editSettingList: (list) => list, - }); - immer$1.enableMapSet(); - immer$1.setAutoFreeze(false); - const store = (...a) => ({ - ...optionSlice(...a), - ...imageSlice(...a), - ...externalLibSlice(...a), - ...operateSlice(...a), - ...scrollbarSlice(...a), - ...otherSlice(...a), - rootRef: { current: null }, - mangaFlowRef: { current: null }, - }); - const useStore = create__default.default()(subscribeWithSelector(immer(store))); - scrollbarCallback(useStore); - imageCallback(useStore); - /** - * 初始化 - */ - const useInit = ({ imgList, fillEffect, option, onExit, onPrev, onNext, onOptionChange, onLoading, editButtonList, editSettingList, }) => { - // 初始化配置 - React.useEffect(() => { - if (!option) - return; - useStore.setState((state) => { - Object.assign(state.option, option); - }); - }, [option]); - const rootRef = React.useRef(null); - React.useEffect(() => { - useStore.setState((state) => { - // 绑定 rootRef - state.rootRef = rootRef; - // 初始化 panzoom - state.initPanzoom(); - }); - }, []); - React.useEffect(() => { - // 初始化页面比例 - useStore.setState((state) => { - state.img.updatePageRatio(state, rootRef.current.scrollWidth, rootRef.current.scrollHeight); - }); - // 在 rootDom 的大小改变时更新比例,并重新计算图片类型 - const resizeObserver = new ResizeObserver(throttle(100, ([entries]) => { - const { width, height } = entries.contentRect; - useStore.setState((state) => { - state.img.updatePageRatio(state, width, height); - }); - })); - resizeObserver.disconnect(); - resizeObserver.observe(rootRef.current); - return () => resizeObserver.disconnect(); - }, []); - // 处理 imgList fillEffect 参数的初始化和修改 - React.useEffect(() => { - useStore.setState((state) => { - if (fillEffect) - state.fillEffect = fillEffect; - // 处理初始化 - if (!state.imgList.length) { - state.imgList = imgList.map((imgUrl) => ({ - type: '', - src: imgUrl, - loadType: 'wait', - })); - state.img.updatePageData.sync(state); - return; - } - /** 修改前的当前显示图片 */ - const oldActiveImg = state.pageList[state.activePageIndex].map((i) => state.imgList?.[i]?.src); - state.imgList = imgList.map((imgUrl) => state.imgList.find((img) => img.src === imgUrl) ?? { - type: '', - src: imgUrl, - loadType: 'wait', - }); - state.img.updatePageData.sync(state); - // 尽量使当前显示的图片在修改后依然不变 - oldActiveImg.some((imgUrl) => { - // 跳过填充页和已被删除的图片 - if (!imgUrl || imgList.includes(imgUrl)) - return false; - const newPageIndex = state.pageList.findIndex((page) => page.some((index) => state.imgList?.[index]?.src === imgUrl)); - if (newPageIndex === -1) - return false; - state.activePageIndex = newPageIndex; - return true; - }); - // 如果已经翻到了最后一页,且最后一页的图片都被删掉了,那就保持在末页显示 - if (state.activePageIndex > state.pageList.length - 1) - state.activePageIndex = state.pageList.length - 1; - }); - }, [imgList, fillEffect]); - React.useEffect(() => { - useStore.setState((state) => { - if (onExit) - state.onExit = onExit; - if (onPrev) - state.onPrev = onPrev; - if (onNext) - state.onNext = onNext; - if (editButtonList) - state.editButtonList = editButtonList; - if (editSettingList) - state.editSettingList = editSettingList; - }); - }, [editButtonList, editSettingList, onExit, onNext, onPrev]); - // 绑定配置发生改变时的回调 - React.useEffect(() => { - if (!onOptionChange) - return undefined; - return useStore.subscribe((state) => state.option, onOptionChange); - }, [onOptionChange]); - // 绑定图片加载状态发生变化时触发的回调 - React.useEffect(() => { - if (!onLoading) - return; - useStore.setState((state) => { - state.onLoading = debounce(100, onLoading); - }); - }, [onLoading]); - return rootRef; - }; - const classes$1 = { "img": "index-module_img__1DxVP", "mangaFlow": "index-module_mangaFlow__Emsh7", "disableZoom": "index-module_disableZoom__SQnsB", "scrollMode": "index-module_scrollMode__vYIgd", "endPage": "index-module_endPage__JITNn", "tip": "index-module_tip__710pO", "toolbar": "index-module_toolbar__0u69J", "toolbarPanel": "index-module_toolbarPanel__tBbg4", "SettingPanelPopper": "index-module_SettingPanelPopper__liZDa", "SettingPanel": "index-module_SettingPanel__GQTbw", "SettingBlock": "index-module_SettingBlock__Yw7Qr", "SettingBlockSubtitle": "index-module_SettingBlockSubtitle__LtLBn", "SettingsItem": "index-module_SettingsItem__UcbhR", "SettingsItemName": "index-module_SettingsItemName__dabYv", "SettingsItemSwitch": "index-module_SettingsItemSwitch__MON2V", "SettingsItemSwitchRound": "index-module_SettingsItemSwitchRound__O9-c9", "SettingsItemIconButton": "index-module_SettingsItemIconButton__nTP1V", "closeCover": "index-module_closeCover__HRd50", "scrollbar": "index-module_scrollbar__wUmnU", "scrollbarDrag": "index-module_scrollbarDrag__wX5Be", "scrollbarPage": "index-module_scrollbarPage__d2B2h", "scrollbarPoper": "index-module_scrollbarPoper__c5XwM", "touchAreaRoot": "index-module_touchAreaRoot__XPLTA", "touchArea": "index-module_touchArea__d6T8h", "hidden": "index-module_hidden__gZmTY", "invisible": "index-module_invisible__HuqQw", "opacity1": "index-module_opacity1__4O7y-", "opacity0": "index-module_opacity0__93ym1", "root": "index-module_root__dkTnB" }; - /** - * 漫画图片 - * - * @param img 图片数据 - */ - const ComicImg = React.memo(({ index }) => { - const imgRef = React.useRef(null); - const handleImgLoaded = React.useCallback(() => { - if (index === -1) - return; - useStore.setState((state) => { - if (!imgRef.current) - return; - const img = state.imgList[index]; - img.loadType = 'loaded'; - img.height = imgRef.current.naturalHeight; - img.width = imgRef.current.naturalWidth; - state.img.updateImgType(img); - // eslint-disable-next-line @typescript-eslint/no-floating-promises - state.onLoading?.(immer$1.current(img), immer$1.current(state.imgList)); - }); - }, [index]); - const handleImgError = React.useCallback((e) => { - if (index === -1) - return; - // 跳过因为 src 为空导致的错误 - if (e.target.getAttribute('src') === '') - return; - useStore.setState((state) => { - const img = state.imgList[index]; - img.loadType = 'error'; - img.error = e; - console.error('图片加载失败', e); - // eslint-disable-next-line @typescript-eslint/no-floating-promises - state.onLoading?.(immer$1.current(img), immer$1.current(state.imgList)); - }); - }, [index]); - const { show, fill } = useStore((state) => { - // 卷轴模式下全部显示 - if (state.option.scrollMode) - return { show: '' }; - const activePage = state.pageList[state.activePageIndex]; - if (!activePage.includes(index)) - return { show: undefined }; - return { - show: '', - fill: (() => { - const i = activePage.indexOf(-1); - if (i === -1) - return undefined; - return !!i === (state.option.dir === 'rtl') ? 'left' : 'right'; - })(), - }; - }, shallow); - const img = useStore((state) => state.imgList[index]); - return (jsxRuntime.jsx("img", { ref: imgRef, className: classes$1.img, src: img.loadType === 'wait' ? '' : img.src, alt: \`\${index}\`, "data-show": show, "data-type": img.type, "data-load-type": img.loadType, "data-fill": fill, onLoad: handleImgLoaded, onError: handleImgError })); - }); - const selector$3 = ({ activePageIndex, imgList, option: { scrollMode, disableZoom, dir }, scrollbar: { handleMangaFlowScroll }, }) => ({ - activePageIndex, - imgList, - scrollMode, - disableZoom, - dir, - handleMangaFlowScroll, - }); - /** - * 漫画图片流的容器 - */ - const ComicImgFlow = () => { - const { imgList, scrollMode, disableZoom, dir, handleMangaFlowScroll } = useStore(selector$3, shallow); - const mangaFlowRef = React.useRef(null); - // 绑定 mangaFlowRef - React.useEffect(() => { - useStore.setState((state) => { - state.mangaFlowRef = mangaFlowRef; - }); - }, []); - const imgEleList = React.useMemo( - // eslint-disable-next-line react/no-array-index-key - () => imgList.map((_, i) => jsxRuntime.jsx(ComicImg, { index: i }, i)), [imgList]); - return (jsxRuntime.jsx("div", { ref: mangaFlowRef, id: classes$1.mangaFlow, className: clsx__default.default(classes$1.mangaFlow, (disableZoom || scrollMode) && classes$1.disableZoom, scrollMode && classes$1.scrollMode), dir: dir, onScroll: handleMangaFlowScroll, children: imgEleList })); - }; - const useHover = () => { - const [isHover, setIsHover] = React.useState(false); - /** 鼠标移入 */ - const handleMouseEnter = React.useCallback(() => { - setIsHover(true); - }, []); - /** 鼠标移出 */ - const handleMouseLeave = React.useCallback(() => { - setIsHover(false); - }, []); - return [isHover, handleMouseEnter, handleMouseLeave]; - }; - var _path$6; - function _extends$6() { _extends$6 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) { - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } - } return target; }; return _extends$6.apply(this, arguments); } - const SvgLooksOne = props => /*#__PURE__*/ React__namespace.createElement("svg", _extends$6({ - xmlns: "http://www.w3.org/2000/svg", - width: "1em", - height: "1em", - viewBox: "0 0 24 24", - role: "img", - stroke: "currentColor", - fill: "currentColor", - strokeWidth: "0" - }, props), _path$6 || (_path$6 = /*#__PURE__*/ React__namespace.createElement("path", { - d: "M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-6 14c-.55 0-1-.45-1-1V9h-1c-.55 0-1-.45-1-1s.45-1 1-1h2c.55 0 1 .45 1 1v8c0 .55-.45 1-1 1z" - }))); - var _path$5; - function _extends$5() { _extends$5 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) { - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } - } return target; }; return _extends$5.apply(this, arguments); } - const SvgLooksTwo = props => /*#__PURE__*/ React__namespace.createElement("svg", _extends$5({ - xmlns: "http://www.w3.org/2000/svg", - width: "1em", - height: "1em", - viewBox: "0 0 24 24", - role: "img", - stroke: "currentColor", - fill: "currentColor", - strokeWidth: "0" - }, props), _path$5 || (_path$5 = /*#__PURE__*/ React__namespace.createElement("path", { - d: "M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-4 8c0 1.1-.9 2-2 2h-2v2h3c.55 0 1 .45 1 1s-.45 1-1 1h-4c-.55 0-1-.45-1-1v-3c0-1.1.9-2 2-2h2V9h-3c-.55 0-1-.45-1-1s.45-1 1-1h3c1.1 0 2 .9 2 2v2z" - }))); - var _path$4; - function _extends$4() { _extends$4 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) { - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } - } return target; }; return _extends$4.apply(this, arguments); } - const SvgViewDay = props => /*#__PURE__*/ React__namespace.createElement("svg", _extends$4({ - xmlns: "http://www.w3.org/2000/svg", - width: "1em", - height: "1em", - viewBox: "0 0 24 24", - role: "img", - stroke: "currentColor", - fill: "currentColor", - strokeWidth: "0" - }, props), _path$4 || (_path$4 = /*#__PURE__*/ React__namespace.createElement("path", { - d: "M3 21h17c.55 0 1-.45 1-1v-1c0-.55-.45-1-1-1H3c-.55 0-1 .45-1 1v1c0 .55.45 1 1 1zM20 8H3c-.55 0-1 .45-1 1v6c0 .55.45 1 1 1h17c.55 0 1-.45 1-1V9c0-.55-.45-1-1-1zM2 4v1c0 .55.45 1 1 1h17c.55 0 1-.45 1-1V4c0-.55-.45-1-1-1H3c-.55 0-1 .45-1 1z" - }))); - var _path$3; - function _extends$3() { _extends$3 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) { - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } - } return target; }; return _extends$3.apply(this, arguments); } - const SvgQueue = props => /*#__PURE__*/ React__namespace.createElement("svg", _extends$3({ - xmlns: "http://www.w3.org/2000/svg", - width: "1em", - height: "1em", - viewBox: "0 0 24 24", - role: "img", - stroke: "currentColor", - fill: "currentColor", - strokeWidth: "0" - }, props), _path$3 || (_path$3 = /*#__PURE__*/ React__namespace.createElement("path", { - d: "M3 6c-.55 0-1 .45-1 1v13c0 1.1.9 2 2 2h13c.55 0 1-.45 1-1s-.45-1-1-1H5c-.55 0-1-.45-1-1V7c0-.55-.45-1-1-1zm17-4H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-2 9h-3v3c0 .55-.45 1-1 1s-1-.45-1-1v-3h-3c-.55 0-1-.45-1-1s.45-1 1-1h3V6c0-.55.45-1 1-1s1 .45 1 1v3h3c.55 0 1 .45 1 1s-.45 1-1 1z" - }))); - var _path$2; - function _extends$2() { _extends$2 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) { - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } - } return target; }; return _extends$2.apply(this, arguments); } - const SvgSettings = props => /*#__PURE__*/ React__namespace.createElement("svg", _extends$2({ - xmlns: "http://www.w3.org/2000/svg", - width: "1em", - height: "1em", - viewBox: "0 0 24 24", - role: "img", - stroke: "currentColor", - fill: "currentColor", - strokeWidth: "0" - }, props), _path$2 || (_path$2 = /*#__PURE__*/ React__namespace.createElement("path", { - d: "M19.5 12c0-.23-.01-.45-.03-.68l1.86-1.41c.4-.3.51-.86.26-1.3l-1.87-3.23a.987.987 0 0 0-1.25-.42l-2.15.91c-.37-.26-.76-.49-1.17-.68l-.29-2.31c-.06-.5-.49-.88-.99-.88h-3.73c-.51 0-.94.38-1 .88l-.29 2.31c-.41.19-.8.42-1.17.68l-2.15-.91c-.46-.2-1-.02-1.25.42L2.41 8.62c-.25.44-.14.99.26 1.3l1.86 1.41a7.343 7.343 0 0 0 0 1.35l-1.86 1.41c-.4.3-.51.86-.26 1.3l1.87 3.23c.25.44.79.62 1.25.42l2.15-.91c.37.26.76.49 1.17.68l.29 2.31c.06.5.49.88.99.88h3.73c.5 0 .93-.38.99-.88l.29-2.31c.41-.19.8-.42 1.17-.68l2.15.91c.46.2 1 .02 1.25-.42l1.87-3.23c.25-.44.14-.99-.26-1.3l-1.86-1.41c.03-.23.04-.45.04-.68zm-7.46 3.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z" - }))); - const classes = { "iconButtonItem": "index-module_iconButtonItem__jb7BZ", "iconButton": "index-module_iconButton__-XHmw", "enabled": "index-module_enabled__NKlE9", "iconButtonPopper": "index-module_iconButtonPopper__vhloV", "hidden": "index-module_hidden__jOPaw" }; - /** - * 图标按钮 - * - * @param param param - */ - const IconButton = React.memo(({ children, tip, hidden, enabled, ref, showTip, placement = 'right', popper, popperClassName, onClick, }) => { - const buttonRef = React.useRef(ref?.current ?? null); - const handleClick = (e) => { - // 在每次点击后取消焦点 - buttonRef.current?.blur(); - return onClick?.(e); - }; - return (jsxRuntime.jsxs("div", { className: classes.iconButtonItem, "data-show": showTip, children: [jsxRuntime.jsx("button", { ref: buttonRef, "aria-label": tip, type: "button", className: clsx__default.default(classes.iconButton, { [classes.hidden]: hidden }, enabled && classes.enabled), onClick: handleClick, children: children }), popper || tip ? (jsxRuntime.jsx("div", { className: clsx__default.default(classes.iconButtonPopper, popperClassName), "data-placement": placement, children: popper || tip })) : null] })); - }); - var _path$1; - function _extends$1() { _extends$1 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) { - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } - } return target; }; return _extends$1.apply(this, arguments); } - const SvgFormatTextdirectionLToR = props => /*#__PURE__*/ React__namespace.createElement("svg", _extends$1({ - xmlns: "http://www.w3.org/2000/svg", - width: "1em", - height: "1em", - viewBox: "0 0 24 24", - role: "img", - stroke: "currentColor", - fill: "currentColor", - strokeWidth: "0" - }, props), _path$1 || (_path$1 = /*#__PURE__*/ React__namespace.createElement("path", { - d: "M9 10v4c0 .55.45 1 1 1s1-.45 1-1V4h2v10c0 .55.45 1 1 1s1-.45 1-1V4h1c.55 0 1-.45 1-1s-.45-1-1-1H9.17C7.08 2 5.22 3.53 5.02 5.61A3.998 3.998 0 0 0 9 10zm11.65 7.65-2.79-2.79a.501.501 0 0 0-.86.35V17H6c-.55 0-1 .45-1 1s.45 1 1 1h11v1.79c0 .45.54.67.85.35l2.79-2.79c.2-.19.2-.51.01-.7z" - }))); - var _path; - function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) { - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } - } return target; }; return _extends.apply(this, arguments); } - const SvgFormatTextdirectionRToL = props => /*#__PURE__*/ React__namespace.createElement("svg", _extends({ - xmlns: "http://www.w3.org/2000/svg", - width: "1em", - height: "1em", - viewBox: "0 0 24 24", - role: "img", - stroke: "currentColor", - fill: "currentColor", - strokeWidth: "0" - }, props), _path || (_path = /*#__PURE__*/ React__namespace.createElement("path", { - d: "M10 10v4c0 .55.45 1 1 1s1-.45 1-1V4h2v10c0 .55.45 1 1 1s1-.45 1-1V4h1c.55 0 1-.45 1-1s-.45-1-1-1h-6.83C8.08 2 6.22 3.53 6.02 5.61A3.998 3.998 0 0 0 10 10zm-2 7v-1.79c0-.45-.54-.67-.85-.35l-2.79 2.79c-.2.2-.2.51 0 .71l2.79 2.79a.5.5 0 0 0 .85-.36V19h11c.55 0 1-.45 1-1s-.45-1-1-1H8z" - }))); - /** - * 设置菜单项 - */ - const SettingsItem = ({ name, className, children, }) => (jsxRuntime.jsxs("div", { className: clsx__default.default(classes$1.SettingsItem, className?.length && className), children: [jsxRuntime.jsxs("div", { className: classes$1.SettingsItemName, children: [" ", name, " "] }), children] })); - /** - * 开关式菜单项 - */ - const SettingsItemSwitch = ({ name, value, className, onChange, }) => { - const handleClick = React.useCallback(() => { - onChange(!value); - }, [onChange, value]); - return (jsxRuntime.jsx(SettingsItem, { name: name, className: className, children: jsxRuntime.jsx("button", { className: classes$1.SettingsItemSwitch, type: "button", onClick: handleClick, "data-checked": value, children: jsxRuntime.jsx("div", { className: classes$1.SettingsItemSwitchRound }) }) })); - }; - /** - * 从 boolean | Element 分出 Element 的类型保护函数 - */ - /** - * 判断使用参数颜色作为默认值时是否需要切换为黑暗模式 - * - * @param hexColor 十六进制颜色。例如 #112233 - */ - const needDarkMode = (hexColor) => { - // 来自 https://24ways.org/2010/calculating-color-contrast - const r = parseInt(hexColor.substring(1, 3), 16); - const g = parseInt(hexColor.substring(3, 5), 16); - const b = parseInt(hexColor.substring(5, 7), 16); - const yiq = (r * 299 + g * 587 + b * 114) / 1000; - return yiq < 128; - }; - /** 默认菜单项 */ - const defaultSettingList = [ - [ - '阅读方向', - () => { - const dir = useStore((state) => state.option.dir); - const handleEditDir = React.useCallback(() => { - useStore.setState((state) => { - state.option.dir = state.option.dir === 'rtl' ? 'ltr' : 'rtl'; - }); - }, []); - return (jsxRuntime.jsx(SettingsItem, { name: dir === 'rtl' ? '从右到左(日漫)' : '从左到右(美漫)', children: jsxRuntime.jsx("button", { className: classes$1.SettingsItemIconButton, type: "button", onClick: handleEditDir, children: dir === 'rtl' ? (jsxRuntime.jsx(SvgFormatTextdirectionRToL, {})) : (jsxRuntime.jsx(SvgFormatTextdirectionLToR, {})) }) })); - }, - ], - [ - '滚动条', - () => { - const enabled = useStore((state) => state.option.scrollbar.enabled); - const handleEnable = React.useCallback(() => { - useStore.setState((state) => { - state.option.scrollbar.enabled = !state.option.scrollbar.enabled; - }); - }, []); - const autoHidden = useStore((state) => state.option.scrollbar.autoHidden); - const handleAutoHidden = React.useCallback(() => { - useStore.setState((state) => { - state.option.scrollbar.autoHidden = - !state.option.scrollbar.autoHidden; - }); - }, []); - const showProgress = useStore((state) => state.option.scrollbar.showProgress); - const handleShowProgress = React.useCallback(() => { - useStore.setState((state) => { - state.option.scrollbar.showProgress = - !state.option.scrollbar.showProgress; - }); - }, []); - return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(SettingsItemSwitch, { name: "\\u663E\\u793A\\u6EDA\\u52A8\\u6761", value: enabled, onChange: handleEnable }), jsxRuntime.jsx(SettingsItemSwitch, { name: "\\u81EA\\u52A8\\u9690\\u85CF\\u6EDA\\u52A8\\u6761", value: autoHidden, className: clsx__default.default(enabled || classes$1.hidden), onChange: handleAutoHidden }), jsxRuntime.jsx(SettingsItemSwitch, { name: "\\u663E\\u793A\\u56FE\\u7247\\u52A0\\u8F7D\\u72B6\\u6001", value: showProgress, className: clsx__default.default(enabled || classes$1.hidden), onChange: handleShowProgress })] })); - }, - ], - [ - '点击翻页', - () => { - /** 是否启用点击翻页功能 */ - const clickPage = useStore((state) => state.option.clickPage.enabled); - const handleClickPages = React.useCallback(() => { - useStore.setState((state) => { - state.option.clickPage.enabled = !state.option.clickPage.enabled; - }); - }, []); - /** 是否显示点击区域 */ - const showTouchArea = useStore((state) => state.showTouchArea); - const handleShowTouchArea = React.useCallback(() => { - useStore.setState((state) => { - state.showTouchArea = !state.showTouchArea; - }); - }, []); - /** 是否左右反转点击区域 */ - const overturn = useStore((state) => state.option.clickPage.overturn); - const handleOverturn = React.useCallback(() => { - useStore.setState((state) => { - state.option.clickPage.overturn = !state.option.clickPage.overturn; - }); - }, []); - return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(SettingsItemSwitch, { name: "\\u542F\\u7528\\u70B9\\u51FB\\u7FFB\\u9875", value: clickPage, onChange: handleClickPages }), jsxRuntime.jsx(SettingsItemSwitch, { name: "\\u5DE6\\u53F3\\u53CD\\u8F6C\\u70B9\\u51FB\\u533A\\u57DF", value: overturn, className: clsx__default.default(!clickPage && classes$1.hidden), onChange: handleOverturn }), jsxRuntime.jsx(SettingsItemSwitch, { name: "\\u663E\\u793A\\u70B9\\u51FB\\u533A\\u57DF\\u63D0\\u793A", value: showTouchArea, className: clsx__default.default(!clickPage && classes$1.hidden), onChange: handleShowTouchArea })] })); - }, - ], - [ - '其他', - () => { - const darkMode = useStore((state) => state.option.darkMode); - const background = useStore((state) => state.option.customBackground); - const handleDarkMode = React.useCallback(() => { - useStore.setState((state) => { - state.option.darkMode = !state.option.darkMode; - }); - }, []); - // eslint-disable-next-line react-hooks/exhaustive-deps - const handleBgColor = React.useCallback((event) => { - useStore.setState((state) => { - // 在拉到纯黑或纯白时改回初始值 - state.option.customBackground = - event.target.value === '#000000' || - event.target.value === '#ffffff' - ? undefined - : event.target.value; - state.option.darkMode = needDarkMode(event.target.value); - }); - }, []); - const disableZoom = useStore((state) => state.option.disableZoom); - const handleDisableZoom = React.useCallback(() => { - useStore.setState((state) => { - state.option.disableZoom = !state.option.disableZoom; - }); - }, []); - const flipToNext = useStore((state) => state.option.flipToNext); - const handleFlipToNext = React.useCallback(() => { - useStore.setState((state) => { - state.option.flipToNext = !state.option.flipToNext; - }); - }, []); - return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(SettingsItemSwitch, { name: "\\u7FFB\\u9875\\u81F3\\u4E0A/\\u4E0B\\u4E00\\u8BDD", value: flipToNext, onChange: handleFlipToNext }), jsxRuntime.jsx(SettingsItemSwitch, { name: "\\u542F\\u7528\\u591C\\u95F4\\u6A21\\u5F0F", value: darkMode, onChange: handleDarkMode }), jsxRuntime.jsx(SettingsItemSwitch, { name: "\\u7981\\u6B62\\u653E\\u5927\\u56FE\\u7247", value: disableZoom, onChange: handleDisableZoom }), jsxRuntime.jsx(SettingsItem, { name: "\\u80CC\\u666F\\u989C\\u8272", children: jsxRuntime.jsx("input", { type: "color", value: background ?? (darkMode ? 'black' : 'white'), onChange: handleBgColor, style: { width: '2em', marginRight: '.4em' } }) })] })); - }, - ], - [ - '关于', - () => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(SettingsItem, { name: "\\u7248\\u672C\\u53F7", children: jsxRuntime.jsx("a", { href: "https://github.com/hymbz/ComicReadScript", children: "0.0.1" }) }), jsxRuntime.jsx(SettingsItem, { name: "\\u53CD\\u9988", children: jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("a", { href: "https://github.com/hymbz/ComicReadScript/issues", style: { marginRight: '.5em' }, children: "Github" }), jsxRuntime.jsx("a", { href: "https://greasyfork.org/zh-CN/scripts/374903-comicread/feedback", children: "Greasy Fork" })] }) })] })), - ], - ]; - /** 菜单面板 */ - const SettingPanel = React.memo(() => { - const editSettingList = useStore((state) => state.editSettingList); - const settingList = React.useMemo(() => editSettingList(defaultSettingList), [editSettingList]); - const handleScroll = React.useCallback((e) => { - e.stopPropagation(); - }, []); - return (jsxRuntime.jsx("div", { className: classes$1.SettingPanel, onScroll: handleScroll, onWheel: handleScroll, children: settingList.map(([key, SettingItem], i) => (jsxRuntime.jsxs(React.Fragment, { children: [i ? jsxRuntime.jsx("hr", {}) : null, jsxRuntime.jsxs("div", { className: classes$1.SettingBlock, children: [jsxRuntime.jsx("div", { className: classes$1.SettingBlockSubtitle, children: key }), jsxRuntime.jsx(SettingItem, {})] })] }, key))) })); - }); - /** 工具栏按钮分隔栏 */ - const buttonListDivider = [ - '', - () => jsxRuntime.jsx("div", { style: { height: '1em' } }), - ]; - /** 工具栏的默认按钮列表 */ - const defaultButtonList = [ - [ - '单双页模式', - () => { - const isOnePageMode = useStore((state) => state.option.onePageMode); - const handleClick = React.useCallback(() => { - useStore.setState((state) => { - state.option.onePageMode = !state.option.onePageMode; - state.img.updatePageData.sync(state); - state.activePageIndex = state.option.onePageMode - ? state.activeImgIndex - : state.pageList.findIndex((page) => page.includes(state.activeImgIndex)); - }); - }, []); - const isScrollMode = useStore((state) => state.option.scrollMode); - return (jsxRuntime.jsx(IconButton, { tip: isOnePageMode ? '单页模式' : '双页模式', onClick: handleClick, hidden: isScrollMode, children: isOnePageMode ? jsxRuntime.jsx(SvgLooksOne, {}) : jsxRuntime.jsx(SvgLooksTwo, {}) })); - }, - ], - [ - '卷轴模式', - () => { - const enabled = useStore((state) => state.option.scrollMode); - const handleClick = React.useCallback(() => { - useStore.setState((state) => { - state.option.scrollMode = !state.option.scrollMode; - state.option.onePageMode = state.option.scrollMode; - state.img.updatePageData.sync(state); - setTimeout(state.scrollbar.handleMangaFlowScroll); - }); - }, []); - return (jsxRuntime.jsx(IconButton, { tip: "\\u5377\\u8F74\\u6A21\\u5F0F", enabled: enabled, onClick: handleClick, children: jsxRuntime.jsx(SvgViewDay, {}) })); - }, - ], - [ - '页面填充', - () => { - const enabled = useStore((state) => state.fillEffect.get(state.nowFillIndex)); - const isOnePageMode = useStore((state) => state.option.onePageMode); - const handleClick = useStore((state) => state.img.switchFillEffect); - return (jsxRuntime.jsx(IconButton, { tip: "\\u9875\\u9762\\u586B\\u5145", enabled: enabled, hidden: isOnePageMode, onClick: handleClick, children: jsxRuntime.jsx(SvgQueue, {}) })); - }, - ], - buttonListDivider, - [ - '设置', - ({ onMouseLeave }) => { - const [showPanel, setShowPanel] = React.useState(false); - const handleClick = React.useCallback(() => { - useStore.setState((state) => { - state.showToolbar = !showPanel; - }); - setShowPanel(!showPanel); - }, [showPanel]); - const popper = React.useMemo(() => (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(SettingPanel, {}), jsxRuntime.jsx("div", { className: classes$1.closeCover, onClick: () => { - handleClick(); - onMouseLeave(); - }, role: "button", tabIndex: -1, "aria-label": "\\u5173\\u95ED\\u8BBE\\u7F6E\\u5F39\\u7A97\\u7684\\u906E\\u7F69" })] })), [handleClick, onMouseLeave]); - return (jsxRuntime.jsx(IconButton, { tip: "\\u8BBE\\u7F6E", enabled: showPanel, showTip: showPanel, onClick: handleClick, popperClassName: showPanel && classes$1.SettingPanelPopper, popper: showPanel && popper, children: jsxRuntime.jsx(SvgSettings, {}) })); - }, - ], - ]; - /** 左侧工具栏 */ - const Toolbar = () => { - const showToolbar = useStore((state) => state.showToolbar); - const [isHover, handleMouseEnter, handleMouseLeave] = useHover(); - const editButtonList = useStore((state) => state.editButtonList); - const buttonList = React.useMemo(() => editButtonList(defaultButtonList).map(([key, ButtonItem], i) => (jsxRuntime.jsx(ButtonItem, { onMouseLeave: handleMouseLeave }, key || i))), [editButtonList, handleMouseLeave]); - return (jsxRuntime.jsx("div", { role: "toolbar", className: classes$1.toolbar, onMouseLeave: handleMouseLeave, onMouseEnter: handleMouseEnter, "data-show": isHover || showToolbar, children: jsxRuntime.jsx("div", { className: classes$1.toolbarPanel, children: buttonList }) })); - }; - const defaultStata = () => ({ - type: 'start', - xy: [0, 0], - initial: [0, 0], - startTime: 0, - }); - const useDrag = (ref, option) => { - const { current: state } = React.useRef(defaultStata()); - React.useEffect(() => { - const { handleDrag } = option; - const controller = new AbortController(); - if (ref.current) { - // 在鼠标、手指按下后切换状态 - ref.current.addEventListener('mousedown', (e) => { - e.stopPropagation(); - // 只处理左键按下触发的事件 - if (e.buttons !== 1) - return; - state.type = 'start'; - state.xy = [e.offsetX, e.offsetY]; - state.initial = [e.offsetX, e.offsetY]; - state.startTime = Date.now(); - handleDrag(state, e); - }, { capture: false, passive: true, signal: controller.signal }); - // TODO: 完成触摸事件的适配 - // ref.current.addEventListener( - // 'touchstart', - // (e) => { - // down.current = true; - // handleDrag(e., e.offsetY); - // }, - // { capture: false, passive: true, signal: controller.signal }, - // ); - // 在鼠标、手指移动时根据状态判断是否要触发函数 - ref.current.addEventListener('mousemove', (e) => { - e.stopPropagation(); - if (state.startTime === 0) - return; - // 只处理左键按下触发的事件 - if (e.buttons !== 1) - return; - state.type = 'dragging'; - state.xy = [e.offsetX, e.offsetY]; - handleDrag(state, e); - }, { capture: false, passive: true, signal: controller.signal }); - // 在鼠标、手指松开后切换状态 - ref.current.addEventListener('mouseup', (e) => { - e.stopPropagation(); - if (state.startTime === 0) - return; - state.type = 'end'; - state.xy = [e.offsetX, e.offsetY]; - handleDrag(state, e); - Object.assign(state, defaultStata()); - }, { capture: false, passive: true, signal: controller.signal }); - } - return () => controller.abort(); - }, [option, ref, state]); - }; - const ScrollbarPage = React.memo(({ index }) => { - const loadType = useStore((state) => state.imgList[index].loadType); - return (jsxRuntime.jsx("div", { className: classes$1.scrollbarPage, "data-index": index, "data-type": loadType })); - }); - const selector$2 = ({ option: { scrollbar, scrollMode }, pageList, showScrollbar, activePageIndex, scrollbar: { dragHeight, dragTop, handleWheel, dragOption, tipText }, }) => ({ - pageList, - showScrollbar, - scrollbar, - scrollMode, - activePageIndex, - dragHeight, - dragTop, - handleWheel, - dragOption, - tipText, - }); - /** 滚动条 */ - const Scrollbar = React.memo(() => { - const { pageList, showScrollbar, scrollbar, scrollMode, activePageIndex, dragHeight, dragTop, handleWheel, dragOption, tipText, } = useStore(selector$2, shallow); - const pageEleList = React.useMemo(() => scrollbar.showProgress - ? pageList.map(([a, b]) => (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx(ScrollbarPage, { index: a !== -1 ? a : b }), b ? jsxRuntime.jsx(ScrollbarPage, { index: b !== -1 ? b : a }) : null] }, \`\${a}\${b}\`))) - : [], [scrollbar.showProgress, pageList]); - const ref = React.useRef(null); - useDrag(ref, dragOption); - return (jsxRuntime.jsxs("div", { ref: ref, className: clsx__default.default(classes$1.scrollbar, { - [classes$1.hidden]: !scrollbar.enabled && !showScrollbar, - }), role: "scrollbar", "aria-controls": classes$1.mangaFlow, "aria-valuenow": activePageIndex || -1, tabIndex: -1, onWheel: handleWheel, children: [jsxRuntime.jsx("div", { className: classes$1.scrollbarDrag, "data-show": !scrollbar.autoHidden || showScrollbar, style: { - top: scrollMode - ? \`\${dragTop * 100}%\` - : \`\${(1 / pageList.length) * 100 * activePageIndex}%\`, - height: dragHeight - ? \`\${dragHeight * 100}%\` - : \`\${(1 / pageList.length) * 100}%\`, - }, children: jsxRuntime.jsx("div", { className: clsx__default.default(classes$1.scrollbarPoper, !tipText && classes$1.hidden), "data-show": showScrollbar, children: tipText }) }), pageEleList] })); - }); - const useDoubleClick = (click, doubleClick, timeout = 200) => { - const clickTimeout = React.useRef(null); - return React.useCallback((event) => { - // 如果点击触发时还有上次计时器的记录,说明这次是双击 - if (clickTimeout.current) { - clearTimeout(clickTimeout.current); - clickTimeout.current = null; - doubleClick?.(event); - return; - } - // 单击事件延迟触发 - clickTimeout.current = window.setTimeout(() => { - click(event); - clickTimeout.current = null; - }, timeout); - }, [click, doubleClick, timeout]); - }; - const selector$1 = ({ showTouchArea, panzoom, turnPage, option: { clickPage, scrollMode, dir }, }) => ({ - showTouchArea, - panzoom, - turnPage, - clickPage, - scrollMode, - dir, - }); - const TouchArea = React.memo(() => { - const { showTouchArea, panzoom, turnPage, clickPage, scrollMode, dir } = useStore(selector$1, shallow); - /** 处理双击缩放 */ - const handleDoubleClickZoom = React.useCallback((e) => { - if (!panzoom) - return; - const { scale } = panzoom.getTransform(); - setTimeout(() => { - // 当缩放到一定程度时再双击会缩放回原尺寸,否则正常触发缩放 - if (scale > 2) - panzoom.smoothZoomAbs(e.clientX, e.clientY, 1); - else - panzoom.smoothZoomAbs(e.clientX, e.clientY, scale + 1); - }); - }, [panzoom]); - const handleClickNext = useDoubleClick(() => { - if (clickPage.enabled) - turnPage('next'); - }, handleDoubleClickZoom); - const handleClickPrev = useDoubleClick(() => { - if (clickPage.enabled) - turnPage('prev'); - }, handleDoubleClickZoom); - const handleClickMenu = useDoubleClick(() => { - useStore.setState((state) => { - state.showScrollbar = !state.showScrollbar; - state.showToolbar = !state.showToolbar; - }); - }, handleDoubleClickZoom); - // 在右键点击时使自身可穿透,使右键菜单为图片的右键菜单 - const [penetrate, setPenetrate] = React.useState(null); - // 之后再立刻恢复回来 - React.useEffect(() => { - setPenetrate(null); - }, [penetrate]); - return (jsxRuntime.jsxs("div", { className: classes$1.touchAreaRoot, style: { - // 开启卷轴模式时隐藏自身 - pointerEvents: penetrate || scrollMode ? 'none' : 'auto', - // 左右方向默认和漫画方向相同,如果开启了左右翻转则翻转 - flexDirection: (dir === 'rtl') === (clickPage.enabled && clickPage.overturn) - ? undefined - : 'row-reverse', - }, onContextMenu: setPenetrate, "data-show": showTouchArea, children: [jsxRuntime.jsx("div", { className: clsx.clsx(classes$1.touchArea), onClick: handleClickPrev, "data-area": "prev", role: "button", tabIndex: -1, children: jsxRuntime.jsx("h6", { children: "\\u4E0A \\u4E00 \\u9875" }) }), jsxRuntime.jsx("div", { className: clsx.clsx(classes$1.touchArea), onClick: handleClickMenu, "data-area": "menu", role: "button", tabIndex: -1, children: jsxRuntime.jsx("h6", { children: "\\u83DC \\u5355" }) }), jsxRuntime.jsx("div", { className: clsx.clsx(classes$1.touchArea), onClick: handleClickNext, "data-area": "next", role: "button", tabIndex: -1, children: jsxRuntime.jsx("h6", { children: "\\u4E0B \\u4E00 \\u9875" }) })] })); - }); - const selector = ({ onExit, onPrev, onNext, turnPage, endPageType, option: { flipToNext }, }) => ({ - onExit, - onPrev, - onNext, - turnPage, - endPageType, - flipToNext, - }); - let delayTypeTimer = 0; - const EndPage = () => { - const { onExit, onPrev, onNext, turnPage, endPageType, flipToNext } = useStore(selector, shallow); - const handleClick = React.useCallback((e) => { - e.stopPropagation(); - if (e.target.nodeName === 'BUTTON') - return; - useStore.setState((state) => { - state.endPageType = undefined; - }); - }, []); - const handleEnd = React.useCallback(() => { - useStore.setState((state) => { - state.onExit?.(true); - state.activePageIndex = 0; - state.endPageType = undefined; - }); - }, []); - const ref = React.useRef(null); - React.useEffect(() => { - const controller = new AbortController(); - ref.current?.addEventListener('wheel', (e) => { - e.preventDefault(); - e.stopPropagation(); - turnPage(e.deltaY > 0 ? 'next' : 'prev'); - }, { - passive: false, - signal: controller.signal, - }); - return () => { - controller.abort(); - }; - }, [turnPage]); - // state.endPageType 变量的延时版本,在隐藏的动画效果结束之后才会真正改变 - // 防止在动画效果结束前 tip 就消失或改变了位置 - const [delayType, setDelayType] = React.useState(); - React.useEffect(() => { - if (endPageType) { - window.clearTimeout(delayTypeTimer); - setDelayType(endPageType); - } - else { - delayTypeTimer = window.setTimeout(() => setDelayType(endPageType), 500); - } - }, [endPageType]); - const tip = React.useMemo(() => { - switch (delayType) { - case 'start': - if (onPrev && flipToNext) - return '已到开头,继续翻页将跳至上一话'; - break; - case 'end': - if (onNext && flipToNext) - return '已到结尾,继续翻页将跳至下一话'; - if (onExit) - return '已到结尾,继续翻页将退出'; - break; - } - return ''; - }, [onNext, onPrev, onExit, delayType, flipToNext]); - return (jsxRuntime.jsxs("div", { ref: ref, className: classes$1.endPage, "data-show": endPageType, "data-type": delayType, onClick: handleClick, role: "button", tabIndex: -1, children: [jsxRuntime.jsx("p", { className: classes$1.tip, children: tip }), jsxRuntime.jsx("button", { className: onPrev ? undefined : classes$1.invisible, onClick: onPrev, type: "button", tabIndex: endPageType ? 0 : -1, children: "\\u4E0A\\u4E00\\u8BDD" }), jsxRuntime.jsx("button", { onClick: handleEnd, type: "button", tabIndex: endPageType ? 0 : -1, "data-is-end": true, children: "\\u9000\\u51FA" }), jsxRuntime.jsx("button", { className: onNext ? undefined : classes$1.invisible, onClick: onNext, type: "button", tabIndex: endPageType ? 0 : -1, children: "\\u4E0B\\u4E00\\u8BDD" })] })); - }; - /** 深色模式的 css 变量 */ - const dark = { - '--hover_bg_color': '#FFF3', - '--hover_bg_color_enable': '#FFFa', - '--switch': '#BDBDBD', - '--switch_bg': '#6E6E6E', - '--scrollbar_drag': '#FFF6', - '--page_bg': '#303030', - '--secondary': '#7A909A', - '--secondary_bg': '#556065', - '--text': 'white', - '--text_secondary': '#FFFC', - '--text_bg': '#121212', - }; - /** 浅色模式的 css 变量 */ - const light = { - '--hover_bg_color': '#0001', - '--hover_bg_color_enable': '#0009', - /* 开关按钮 */ - '--switch': '#FAFAFA', - /* 开关滑轨 */ - '--switch_bg': '#9C9C9C', - /* 滚动条 */ - '--scrollbar_drag': '#0006', - '--page_bg': 'white', - '--secondary': '#7A909A', - '--secondary_bg': '#BAC5CA', - '--text': 'black', - '--text_secondary': '#0008', - '--text_bg': '#FAFAFA', - }; - const useCssVar = () => { - const bg = useStore((state) => state.option.customBackground); - const darkMode = useStore((state) => state.option.darkMode); - return React.useMemo(() => ({ - '--bg': bg ?? (darkMode ? 'black' : 'white'), - ...(darkMode ? dark : light), - }), [bg, darkMode]); - }; - /** - * 漫画组件 - */ - const Manga = (props) => { - const rootRef = useInit(props); - const cssVar = useCssVar(); - const handleScroll = useStore((state) => state.handleScroll); - const handleKeyUp = useStore((state) => state.handleKeyUp); - React.useEffect(() => { - rootRef.current?.focus(); - }); - return (jsxRuntime.jsxs("div", { className: classes$1.root, ref: rootRef, style: cssVar, onWheel: handleScroll, onKeyUp: handleKeyUp, role: "presentation", tabIndex: -1, children: [jsxRuntime.jsx(Toolbar, {}), jsxRuntime.jsx(ComicImgFlow, {}), jsxRuntime.jsx(Scrollbar, {}), jsxRuntime.jsx(TouchArea, {}), jsxRuntime.jsx(EndPage, {})] })); - }; - exports.Manga = Manga; - exports.buttonListDivider = buttonListDivider; - }; - const selfModule = module.exports; - module.exports = new Proxy(selfModule, { - get(_, prop) { - if (selfModule[prop] === undefined) - main(); - return selfModule[prop]; - }, - apply(_, __, args) { - if (selfModule[prop] === undefined) - main(); - return selfModule[prop](...args); - }, - construct(_, args) { - if (selfModule[prop] === undefined) - main(); - return new selfModule[prop](...args); - }, - }); -}(Manga, Manga.exports)); - -/** 为工具栏加上下载和退出按钮 */ -const setToolbarButton = (draftProps) => { - /** 下载按钮 */ - const DownloadButton = () => { - const [tip, setTip] = React.useState('下载'); - const handleDownload = React.useCallback(async () => { - const { imgList } = draftProps; - const fileData = {}; - const imgIndexNum = \`\${imgList.length}\`.length; - for (let i = 0; i < imgList.length; i += 1) { - setTip(\`下载中 - \${i}/\${imgList.length}\`); - const index = \`\${\`\${i}\`.padStart(imgIndexNum, '0')}\`; - const fileExt = imgList[i].split('.').at(-1); - const fileName = \`\${index}.\${fileExt}\`; - try { - // eslint-disable-next-line no-await-in-loop - const res = await request(imgList[i], { - responseType: 'arraybuffer', - }); - fileData[fileName] = new Uint8Array(res.response); - } - catch (error) { - reactToastify.toast.error(\`\${fileName} 下载失败\`); - fileData[\`\${index} - 下载失败.\${fileExt}\`] = new Uint8Array(); - } - } - setTip('开始打包'); - const zipped = fflate__default.default.zipSync(fileData, { - level: 0, - comment: window.location.href, - }); - saveAs(new Blob([zipped]), \`\${document.title}.zip\`); - setTip('下载完成'); - }, []); - return (require$$0.jsx(IconButton.exports.IconButton, { tip: tip, onClick: handleDownload, children: require$$0.jsx(SvgFileDownload, {}) })); - }; - const handleEnd = () => draftProps.onExit?.(); - draftProps.editButtonList = (list) => { - // 在设置按钮上方放置下载按钮 - list.splice(-1, 0, ['下载', DownloadButton]); - return [ - ...list, - // 再在最下面添加分隔栏和退出按钮 - Manga.exports.buttonListDivider, - [ - '退出', - () => (require$$0.jsx(IconButton.exports.IconButton, { tip: "\\u9000\\u51FA", onClick: handleEnd, children: require$$0.jsx(SvgClose, {}) })), - ], - ]; - }; - return draftProps; -}; - -var _path$7; -function _extends$7() { _extends$7 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$7.apply(this, arguments); } -const SvgAutoFixHigh = props => /*#__PURE__*/React__namespace.createElement("svg", _extends$7({ - xmlns: "http://www.w3.org/2000/svg", - width: "1em", - height: "1em", - viewBox: "0 0 24 24", - role: "img", - stroke: "currentColor", - fill: "currentColor", - strokeWidth: "0" -}, props), _path$7 || (_path$7 = /*#__PURE__*/React__namespace.createElement("path", { - d: "m20.45 6 .49-1.06L22 4.45a.5.5 0 0 0 0-.91l-1.06-.49L20.45 2a.5.5 0 0 0-.91 0l-.49 1.06-1.05.49a.5.5 0 0 0 0 .91l1.06.49.49 1.05c.17.39.73.39.9 0zM8.95 6l.49-1.06 1.06-.49a.5.5 0 0 0 0-.91l-1.06-.48L8.95 2a.492.492 0 0 0-.9 0l-.49 1.06-1.06.49a.5.5 0 0 0 0 .91l1.06.49L8.05 6c.17.39.73.39.9 0zm10.6 7.5-.49 1.06-1.06.49a.5.5 0 0 0 0 .91l1.06.49.49 1.06a.5.5 0 0 0 .91 0l.49-1.06 1.05-.5a.5.5 0 0 0 0-.91l-1.06-.49-.49-1.06c-.17-.38-.73-.38-.9.01zm-1.84-4.38-2.83-2.83a.996.996 0 0 0-1.41 0L2.29 17.46a.996.996 0 0 0 0 1.41l2.83 2.83c.39.39 1.02.39 1.41 0L17.7 10.53c.4-.38.4-1.02.01-1.41zm-3.5 2.09L12.8 9.8l1.38-1.38 1.41 1.41-1.38 1.38z" -}))); - -var _path$6; -function _extends$6() { _extends$6 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$6.apply(this, arguments); } -const SvgAutoFixOff = props => /*#__PURE__*/React__namespace.createElement("svg", _extends$6({ - xmlns: "http://www.w3.org/2000/svg", - width: "1em", - height: "1em", - viewBox: "0 0 24 24", - role: "img", - stroke: "currentColor", - fill: "currentColor", - strokeWidth: "0" -}, props), _path$6 || (_path$6 = /*#__PURE__*/React__namespace.createElement("path", { - d: "m22 3.55-1.06-.49L20.45 2a.5.5 0 0 0-.91 0l-.49 1.06-1.05.49a.5.5 0 0 0 0 .91l1.06.49.49 1.05a.5.5 0 0 0 .91 0l.49-1.06L22 4.45c.39-.17.39-.73 0-.9zm-7.83 4.87 1.41 1.41-1.46 1.46 1.41 1.41 2.17-2.17a.996.996 0 0 0 0-1.41l-2.83-2.83a.996.996 0 0 0-1.41 0l-2.17 2.17 1.41 1.41 1.47-1.45zM2.1 4.93l6.36 6.36-6.17 6.17a.996.996 0 0 0 0 1.41l2.83 2.83c.39.39 1.02.39 1.41 0l6.17-6.17 6.36 6.36a.996.996 0 1 0 1.41-1.41L3.51 3.51a.996.996 0 0 0-1.41 0c-.39.4-.39 1.03 0 1.42z" -}))); - -var _path$5; -function _extends$5() { _extends$5 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$5.apply(this, arguments); } -const SvgFlashOn = props => /*#__PURE__*/React__namespace.createElement("svg", _extends$5({ - xmlns: "http://www.w3.org/2000/svg", - width: "1em", - height: "1em", - viewBox: "0 0 24 24", - role: "img", - stroke: "currentColor", - fill: "currentColor", - strokeWidth: "0" -}, props), _path$5 || (_path$5 = /*#__PURE__*/React__namespace.createElement("path", { - d: "M7 3v9c0 .55.45 1 1 1h2v7.15c0 .51.67.69.93.25l5.19-8.9a.995.995 0 0 0-.86-1.5H13l2.49-6.65A.994.994 0 0 0 14.56 2H8c-.55 0-1 .45-1 1z" -}))); - -var _path$4; -function _extends$4() { _extends$4 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$4.apply(this, arguments); } -const SvgFlashOff = props => /*#__PURE__*/React__namespace.createElement("svg", _extends$4({ - xmlns: "http://www.w3.org/2000/svg", - width: "1em", - height: "1em", - viewBox: "0 0 24 24", - role: "img", - stroke: "currentColor", - fill: "currentColor", - strokeWidth: "0" -}, props), _path$4 || (_path$4 = /*#__PURE__*/React__namespace.createElement("path", { - d: "M16.12 11.5a.995.995 0 0 0-.86-1.5h-1.87l2.28 2.28.45-.78zm.16-8.05c.33-.67-.15-1.45-.9-1.45H8c-.55 0-1 .45-1 1v.61l6.13 6.13 3.15-6.29zm2.16 14.43L4.12 3.56a.996.996 0 1 0-1.41 1.41L7 9.27V12c0 .55.45 1 1 1h2v7.15c0 .51.67.69.93.25l2.65-4.55 3.44 3.44c.39.39 1.02.39 1.41 0 .4-.39.4-1.02.01-1.41z" -}))); - -const defaultSpeedDial = (options, setOptions) => { - const DefaultButton = ({ optionName, showName, children }) => { - return (require$$0.jsx(IconButton.exports.IconButton, { tip: showName ?? optionName, placement: "left", onClick: () => setOptions({ ...options, [optionName]: !options[optionName] }), children: children ?? - (options[optionName] ? require$$0.jsx(SvgAutoFixHigh, {}) : require$$0.jsx(SvgAutoFixOff, {})) })); - }; - const list = Object.keys(options).map((optionName) => { - switch (optionName) { - case 'hiddenFAB': - case 'option': - return null; - case 'autoShow': - return () => (require$$0.jsx(DefaultButton, { optionName: "autoShow", showName: "\\u81EA\\u52A8\\u8FDB\\u5165\\u9605\\u8BFB\\u6A21\\u5F0F", children: options.autoShow ? require$$0.jsx(SvgFlashOn, {}) : require$$0.jsx(SvgFlashOff, {}) })); - default: - return () => require$$0.jsx(DefaultButton, { optionName: optionName }); - } - }); - return list.filter(Boolean); -}; - -const promisifyRequest = (request) => new Promise((resolve, reject) => { - // eslint-disable-next-line no-multi-assign - request.oncomplete = request.onsuccess = () => resolve(request.result); - // eslint-disable-next-line no-multi-assign - request.onabort = request.onerror = () => reject(request.error); -}); -const useCache = (initSchema, version = 1) => { - const request = indexedDB.open('ComicReadScript', version); - request.onupgradeneeded = () => { - initSchema(request.result); - }; - const dbp = promisifyRequest(request); - const useStore = (storeName, txMode, callback) => dbp.then((db) => callback(db.transaction(storeName, txMode).objectStore(storeName))); - return { - /** 存入数据 */ - set: (storeName, value) => useStore(storeName, 'readwrite', async (store) => { - store.put(value); - await promisifyRequest(store.transaction); - }), - /** 根据主键直接获取数据 */ - get: (storeName, query) => useStore(storeName, 'readonly', (store) => promisifyRequest(store.get(query))), - /** 查找符合条件的数据 */ - find: (storeName, query, index) => useStore(storeName, 'readonly', (store) => promisifyRequest((index ? store.index(index) : store).getAll(query))), - /** 删除符合条件的数据 */ - del: (storeName, query, index) => useStore(storeName, 'readwrite', async (store) => { - if (index) { - store.index(index).openCursor(query).onsuccess = - async function onsuccess() { - if (!this.result) - return; - await promisifyRequest(this.result.delete()); - this.result.continue(); - }; - await promisifyRequest(store.transaction); - } - else { - store.delete(query); - await promisifyRequest(store.transaction); - } - }), - // each: ( - // storeName: K, - // query: IDBValidKey | IDBKeyRange | null, - // callback: (cursor: IDBCursorWithValue) => void, - // ) => - // useStore(storeName, 'readonly', (store) => { - // store.openCursor(query).onsuccess = function onsuccess() { - // if (!this.result) return; - // callback(this.result); - // this.result.continue(); - // }; - // return promisifyRequest(store.transaction); - // }), - }; -}; - -const MangaStyle = ".index-module_img__1DxVP{display:none;height:100%;max-width:100%;object-fit:contain}.index-module_img__1DxVP[data-show]{display:unset}.index-module_img__1DxVP[data-load-type=error],.index-module_img__1DxVP[data-load-type=wait]{visibility:hidden}.index-module_img__1DxVP[data-fill=left]{transform:translate(50%)}.index-module_img__1DxVP[data-fill=right]{transform:translate(-50%)}.index-module_mangaFlow__Emsh7{align-items:center;background-color:var(--bg);color:var(--text);display:flex;height:100%;justify-content:center;user-select:none}.index-module_mangaFlow__Emsh7.index-module_disableZoom__SQnsB .index-module_img__1DxVP{height:unset;max-height:100%;object-fit:scale-down}.index-module_mangaFlow__Emsh7.index-module_scrollMode__vYIgd{flex-direction:column;justify-content:flex-start;overflow:auto;scrollbar-width:none}.index-module_mangaFlow__Emsh7.index-module_scrollMode__vYIgd::-webkit-scrollbar{display:none}.index-module_mangaFlow__Emsh7.index-module_scrollMode__vYIgd .index-module_img__1DxVP{height:auto;max-height:unset;max-width:100%}.index-module_mangaFlow__Emsh7[dir=ltr]{flex-direction:row}.index-module_endPage__JITNn{align-items:center;background-color:#3339;color:#fff;display:flex;height:100%;justify-content:center;left:0;opacity:0;pointer-events:none;position:absolute;top:0;transition:opacity .5s;width:100%;z-index:10}.index-module_endPage__JITNn>button{background-color:initial;border:0;color:inherit;cursor:pointer;font-size:1.2em}.index-module_endPage__JITNn>button[data-is-end]{font-size:3em;margin:2em}.index-module_endPage__JITNn>button:focus-visible{outline:none}.index-module_endPage__JITNn>.index-module_tip__710pO{margin:auto;position:absolute}.index-module_endPage__JITNn[data-show]{opacity:1;pointer-events:all}.index-module_endPage__JITNn[data-type=start]>.index-module_tip__710pO{transform:translateY(-40vh)}.index-module_endPage__JITNn[data-type=end]>.index-module_tip__710pO{transform:translateY(40vh)}.index-module_toolbar__0u69J{align-items:center;display:flex;height:100%;justify-content:flex-start;position:fixed;width:5vw;z-index:9}.index-module_toolbarPanel__tBbg4{display:flex;flex-direction:column;padding:1em 1em 1em .5em;transform:translateX(-100%);transition:transform .2s}.index-module_toolbar__0u69J[data-show=true] .index-module_toolbarPanel__tBbg4{transform:none}.index-module_SettingPanelPopper__liZDa{height:0!important;padding:0!important;transform:none!important}.index-module_SettingPanel__GQTbw{background-color:var(--page_bg);border-radius:.3em;bottom:0;box-shadow:0 3px 1px -2px #0003,0 2px 2px 0 #00000024,0 1px 5px 0 #0000001f;color:var(--text);font-size:1.2em;height:-moz-fit-content;height:fit-content;margin:auto;max-height:95vh;overflow:auto;position:fixed;scrollbar-width:none;top:0;width:15em}.index-module_SettingPanel__GQTbw::-webkit-scrollbar{display:none}.index-module_SettingBlock__Yw7Qr{padding:.5em}.index-module_SettingBlockSubtitle__LtLBn{color:var(--text_secondary);font-size:.7em;margin-bottom:-.3em}.index-module_SettingsItem__UcbhR{align-items:center;display:flex;justify-content:space-between;margin-top:1em}.index-module_SettingsItemName__dabYv{font-size:.9em}.index-module_SettingsItemSwitch__MON2V{align-items:center;background-color:var(--switch_bg);border:0;border-radius:1em;cursor:pointer;display:inline-flex;height:.8em;margin-right:.3em;padding:0;width:2.3em}.index-module_SettingsItemSwitchRound__O9-c9{background:var(--switch);border-radius:100%;box-shadow:0 2px 1px -1px #0003,0 1px 1px 0 #00000024,0 1px 3px 0 #0000001f;height:1.15em;transform:translateX(-10%);transition:transform .1s;width:1.15em}.index-module_SettingsItemSwitch__MON2V[data-checked=true]{background:var(--secondary_bg)}.index-module_SettingsItemSwitch__MON2V[data-checked=true] .index-module_SettingsItemSwitchRound__O9-c9{background:var(--secondary);transform:translateX(110%)}.index-module_SettingsItemIconButton__nTP1V{background-color:initial;border:none;color:var(--text);cursor:pointer;font-size:1.7em;height:1em;margin:0;padding:0;position:absolute;right:.7em}.index-module_closeCover__HRd50{height:100%;left:0;position:fixed;top:0;width:100%;z-index:-1}.index-module_scrollbar__wUmnU{border-left:10em solid #0000;display:flex;flex-direction:column;height:98%;outline:none;position:absolute;right:3px;top:1%;touch-action:none;user-select:none;width:5px;z-index:9}.index-module_scrollbar__wUmnU>div{display:flex;flex-direction:column;flex-grow:1;pointer-events:none}.index-module_scrollbarDrag__wX5Be{background-color:var(--scrollbar_drag);border-radius:1em;justify-content:center;opacity:0;position:absolute;transition:top .15s;width:100%;z-index:1}.index-module_scrollbarPage__d2B2h{flex-grow:1;transform:scaleY(1);transform-origin:bottom;transition:transform 1s,background-color 0ms 1s}.index-module_scrollbarPage__d2B2h[data-type=loaded]{transform:scaleY(0)}.index-module_scrollbarPage__d2B2h[data-type=loading]{background-color:var(--secondary)}.index-module_scrollbarPage__d2B2h[data-type=wait]{background-color:var(--secondary);opacity:.5}.index-module_scrollbarPage__d2B2h[data-type=error]{background-color:#f005}.index-module_scrollbarPoper__c5XwM{align-items:center;background-color:#303030;border-radius:.3em;color:#fff;display:flex;font-size:.8em;line-height:1.5em;opacity:0;padding:.2em .5em;position:absolute;right:2em;text-align:center;transition:opacity .15s;white-space:pre;width:-moz-fit-content;width:fit-content}.index-module_scrollbarPoper__c5XwM:after{background-color:#303030;background-color:initial;border:.4em solid #0000;border-left:.5em solid #303030;content:\\"\\";left:100%;position:absolute}.index-module_scrollbarDrag__wX5Be[data-show=true],.index-module_scrollbarPoper__c5XwM[data-show=true],.index-module_scrollbar__wUmnU:hover .index-module_scrollbarDrag__wX5Be,.index-module_scrollbar__wUmnU:hover .index-module_scrollbarPoper__c5XwM{opacity:1}.index-module_touchAreaRoot__XPLTA{color:#0000;display:flex;font-size:3em;height:100%;position:absolute;top:0;user-select:none;width:100%}.index-module_touchArea__d6T8h{align-items:center;display:flex;flex-grow:1;justify-content:center;outline:none;writing-mode:vertical-rl;z-index:1}.index-module_touchArea__d6T8h[data-area=menu]{flex-basis:0}.index-module_touchAreaRoot__XPLTA[data-show=true] .index-module_touchArea__d6T8h{color:#fff}.index-module_touchAreaRoot__XPLTA[data-show=true] .index-module_touchArea__d6T8h[data-area=prev]{background-color:#95e1d3e6}.index-module_touchAreaRoot__XPLTA[data-show=true] .index-module_touchArea__d6T8h[data-area=menu]{background-color:#fce38ae6}.index-module_touchAreaRoot__XPLTA[data-show=true] .index-module_touchArea__d6T8h[data-area=next]{background-color:#f38181e6}.index-module_hidden__gZmTY{display:none}.index-module_invisible__HuqQw{visibility:hidden}.index-module_opacity1__4O7y-{opacity:1}.index-module_opacity0__93ym1{opacity:0}.index-module_root__dkTnB{height:100%;outline:0;overflow:hidden;position:relative;width:100%}a{color:var(--text_secondary)}\\n.index-module_iconButtonItem__jb7BZ{align-items:center;display:flex;position:relative}.index-module_iconButton__-XHmw{align-items:center;background-color:var(--text_bg,#121212);border-radius:9999px;border-style:none;color:var(--text,#fff);cursor:pointer;display:flex;font-size:1.5em;height:1.5em;justify-content:center;margin:.1em;outline:none;padding:0;width:1.5em}.index-module_iconButton__-XHmw:focus,.index-module_iconButton__-XHmw:hover{background-color:var(--hover_bg_color,#fff3)}.index-module_iconButton__-XHmw.index-module_enabled__NKlE9{background-color:var(--text,#fff);color:var(--text_bg,#121212)}.index-module_iconButton__-XHmw.index-module_enabled__NKlE9:focus,.index-module_iconButton__-XHmw.index-module_enabled__NKlE9:hover{background-color:var(--hover_bg_color_enable,#fffa)}.index-module_iconButtonPopper__vhloV{align-items:center;background-color:#303030;border-radius:.3em;color:#fff;display:flex;font-size:.8em;opacity:0;padding:.4em .5em;position:absolute;top:50%;transform:translateY(-50%);white-space:nowrap}.index-module_iconButtonPopper__vhloV[data-placement=right]{left:calc(100% + 1.5em)}.index-module_iconButtonPopper__vhloV[data-placement=right]:before{border-right-color:var(--switch_bg,#6e6e6e);border-right-width:.5em;right:calc(100% + .5em)}.index-module_iconButtonPopper__vhloV[data-placement=left]{right:calc(100% + 1.5em)}.index-module_iconButtonPopper__vhloV[data-placement=left]:before{border-left-color:var(--switch_bg,#6e6e6e);border-left-width:.5em;left:calc(100% + .5em)}.index-module_iconButtonPopper__vhloV:before{background-color:initial;border:.4em solid #0000;content:\\"\\";position:absolute;transition:opacity .15s}.index-module_iconButtonItem__jb7BZ:focus .index-module_iconButtonPopper__vhloV,.index-module_iconButtonItem__jb7BZ:hover .index-module_iconButtonPopper__vhloV,.index-module_iconButtonItem__jb7BZ[data-show=true] .index-module_iconButtonPopper__vhloV{opacity:1}.index-module_hidden__jOPaw{display:none}"; - -const IconBottonStyle = ".index-module_iconButtonItem__jb7BZ{align-items:center;display:flex;position:relative}.index-module_iconButton__-XHmw{align-items:center;background-color:var(--text_bg,#121212);border-radius:9999px;border-style:none;color:var(--text,#fff);cursor:pointer;display:flex;font-size:1.5em;height:1.5em;justify-content:center;margin:.1em;outline:none;padding:0;width:1.5em}.index-module_iconButton__-XHmw:focus,.index-module_iconButton__-XHmw:hover{background-color:var(--hover_bg_color,#fff3)}.index-module_iconButton__-XHmw.index-module_enabled__NKlE9{background-color:var(--text,#fff);color:var(--text_bg,#121212)}.index-module_iconButton__-XHmw.index-module_enabled__NKlE9:focus,.index-module_iconButton__-XHmw.index-module_enabled__NKlE9:hover{background-color:var(--hover_bg_color_enable,#fffa)}.index-module_iconButtonPopper__vhloV{align-items:center;background-color:#303030;border-radius:.3em;color:#fff;display:flex;font-size:.8em;opacity:0;padding:.4em .5em;position:absolute;top:50%;transform:translateY(-50%);white-space:nowrap}.index-module_iconButtonPopper__vhloV[data-placement=right]{left:calc(100% + 1.5em)}.index-module_iconButtonPopper__vhloV[data-placement=right]:before{border-right-color:var(--switch_bg,#6e6e6e);border-right-width:.5em;right:calc(100% + .5em)}.index-module_iconButtonPopper__vhloV[data-placement=left]{right:calc(100% + 1.5em)}.index-module_iconButtonPopper__vhloV[data-placement=left]:before{border-left-color:var(--switch_bg,#6e6e6e);border-left-width:.5em;left:calc(100% + .5em)}.index-module_iconButtonPopper__vhloV:before{background-color:initial;border:.4em solid #0000;content:\\"\\";position:absolute;transition:opacity .15s}.index-module_iconButtonItem__jb7BZ:focus .index-module_iconButtonPopper__vhloV,.index-module_iconButtonItem__jb7BZ:hover .index-module_iconButtonPopper__vhloV,.index-module_iconButtonItem__jb7BZ[data-show=true] .index-module_iconButtonPopper__vhloV{opacity:1}.index-module_hidden__jOPaw{display:none}"; - -/** - * 显示漫画阅读窗口 - */ -const useManga = async (initProps) => { - const [root, dom] = useComponentsRoot('comicRead'); - await GM.addStyle(\` - #comicRead > div { - position: fixed; - z-index: 999999999; - top: 0; - left: 0; - - width: 100vw; - height: 100vh; - - font-size: 16px; - - opacity: 1; - - transition: opacity 300ms, transform 100ms; - } - - #comicRead.hidden > div { - transform: scale(0); - - opacity: 0; - - transition: opacity 300ms, transform 0s 300ms; - } - \`); - const props = { imgList: [], show: false, ...initProps }; - const set = (recipe, render = true) => { - if (recipe) { - Object.assign(props, typeof recipe === 'function' ? recipe(props) : recipe); - } - if (!render) - return; - root.render(require$$0.jsxs(shadow__default.default.div, { children: [require$$0.jsx(Manga.exports.Manga, { ...props }), require$$0.jsx("style", { type: "text/css", children: IconBottonStyle }), require$$0.jsx("style", { type: "text/css", children: MangaStyle })] })); - if (props.imgList.length > 1 && props.show) { - dom.className = ''; - document.documentElement.style.overflow = 'hidden'; - } - else { - dom.className = 'hidden'; - document.documentElement.style.overflow = 'unset'; - } - }; - props.onExit = () => { - set({ show: false }); - }; - return [set, props]; -}; - -var _path$3, _path2; -function _extends$3() { _extends$3 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$3.apply(this, arguments); } -const SvgMenuBook = props => /*#__PURE__*/React__namespace.createElement("svg", _extends$3({ - xmlns: "http://www.w3.org/2000/svg", - width: "1em", - height: "1em", - viewBox: "0 0 24 24", - role: "img", - stroke: "currentColor", - fill: "currentColor", - strokeWidth: "0" -}, props), _path$3 || (_path$3 = /*#__PURE__*/React__namespace.createElement("path", { - d: "M17.5 4.5c-1.95 0-4.05.4-5.5 1.5-1.45-1.1-3.55-1.5-5.5-1.5-1.45 0-2.99.22-4.28.79C1.49 5.62 1 6.33 1 7.14v11.28c0 1.3 1.22 2.26 2.48 1.94.98-.25 2.02-.36 3.02-.36 1.56 0 3.22.26 4.56.92.6.3 1.28.3 1.87 0 1.34-.67 3-.92 4.56-.92 1 0 2.04.11 3.02.36 1.26.33 2.48-.63 2.48-1.94V7.14c0-.81-.49-1.52-1.22-1.85-1.28-.57-2.82-.79-4.27-.79zM21 17.23c0 .63-.58 1.09-1.2.98-.75-.14-1.53-.2-2.3-.2-1.7 0-4.15.65-5.5 1.5V8c1.35-.85 3.8-1.5 5.5-1.5.92 0 1.83.09 2.7.28.46.1.8.51.8.98v9.47z" -})), _path2 || (_path2 = /*#__PURE__*/React__namespace.createElement("path", { - d: "M13.98 11.01c-.32 0-.61-.2-.71-.52-.13-.39.09-.82.48-.94 1.54-.5 3.53-.66 5.36-.45.41.05.71.42.66.83-.05.41-.42.71-.83.66-1.62-.19-3.39-.04-4.73.39-.08.01-.16.03-.23.03zm0 2.66c-.32 0-.61-.2-.71-.52-.13-.39.09-.82.48-.94 1.53-.5 3.53-.66 5.36-.45.41.05.71.42.66.83-.05.41-.42.71-.83.66-1.62-.19-3.39-.04-4.73.39a.97.97 0 0 1-.23.03zm0 2.66c-.32 0-.61-.2-.71-.52-.13-.39.09-.82.48-.94 1.53-.5 3.53-.66 5.36-.45.41.05.71.42.66.83-.05.41-.42.7-.83.66-1.62-.19-3.39-.04-4.73.39a.97.97 0 0 1-.23.03z" -}))); - -var _path$2; -function _extends$2() { _extends$2 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$2.apply(this, arguments); } -const SvgImageSearch = props => /*#__PURE__*/React__namespace.createElement("svg", _extends$2({ - xmlns: "http://www.w3.org/2000/svg", - width: "1em", - height: "1em", - viewBox: "0 0 24 24", - role: "img", - stroke: "currentColor", - fill: "currentColor", - strokeWidth: "0" -}, props), _path$2 || (_path$2 = /*#__PURE__*/React__namespace.createElement("path", { - d: "M18 15v4c0 .55-.45 1-1 1H5c-.55 0-1-.45-1-1V7c0-.55.45-1 1-1h3.02c.55 0 1-.45 1-1s-.45-1-1-1H4c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-5c0-.55-.45-1-1-1s-1 .45-1 1zm-2.5 3H6.52c-.42 0-.65-.48-.39-.81l1.74-2.23a.5.5 0 0 1 .78-.01l1.56 1.88 2.35-3.02c.2-.26.6-.26.79.01l2.55 3.39c.25.32.01.79-.4.79zm3.8-9.11c.48-.77.75-1.67.69-2.66-.13-2.15-1.84-3.97-3.97-4.2A4.5 4.5 0 0 0 11 6.5c0 2.49 2.01 4.5 4.49 4.5.88 0 1.7-.26 2.39-.7l2.41 2.41c.39.39 1.03.39 1.42 0 .39-.39.39-1.03 0-1.42l-2.41-2.4zM15.5 9a2.5 2.5 0 0 1 0-5 2.5 2.5 0 0 1 0 5z" -}))); - -var _path$1; -function _extends$1() { _extends$1 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$1.apply(this, arguments); } -const SvgImportContacts = props => /*#__PURE__*/React__namespace.createElement("svg", _extends$1({ - xmlns: "http://www.w3.org/2000/svg", - width: "1em", - height: "1em", - viewBox: "0 0 24 24", - role: "img", - stroke: "currentColor", - fill: "currentColor", - strokeWidth: "0" -}, props), _path$1 || (_path$1 = /*#__PURE__*/React__namespace.createElement("path", { - d: "M17.5 4.5c-1.95 0-4.05.4-5.5 1.5-1.45-1.1-3.55-1.5-5.5-1.5-1.45 0-2.99.22-4.28.79C1.49 5.62 1 6.33 1 7.14v11.28c0 1.3 1.22 2.26 2.48 1.94.98-.25 2.02-.36 3.02-.36 1.56 0 3.22.26 4.56.92.6.3 1.28.3 1.87 0 1.34-.67 3-.92 4.56-.92 1 0 2.04.11 3.02.36 1.26.33 2.48-.63 2.48-1.94V7.14c0-.81-.49-1.52-1.22-1.85-1.28-.57-2.82-.79-4.27-.79zM21 17.23c0 .63-.58 1.09-1.2.98-.75-.14-1.53-.2-2.3-.2-1.7 0-4.15.65-5.5 1.5V8c1.35-.85 3.8-1.5 5.5-1.5.92 0 1.83.09 2.7.28.46.1.8.51.8.98v9.47z" -}))); - -var _path; -function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } -const SvgCloudDownload = props => /*#__PURE__*/React__namespace.createElement("svg", _extends({ - xmlns: "http://www.w3.org/2000/svg", - width: "1em", - height: "1em", - viewBox: "0 0 24 24", - role: "img", - stroke: "currentColor", - fill: "currentColor", - strokeWidth: "0" -}, props), _path || (_path = /*#__PURE__*/React__namespace.createElement("path", { - d: "M19.35 10.04A7.49 7.49 0 0 0 12 4C9.11 4 6.6 5.64 5.35 8.04A5.994 5.994 0 0 0 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM17 13l-4.65 4.65c-.2.2-.51.2-.71 0L7 13h3V9h4v4h3z" -}))); - -var Fab = {exports: {}}; - -(function (module, exports) { - Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } }); - const main = () => { - const jsxRuntime = require$$0__default.default; - const React = React__default.default; - function _interopNamespace(e) { - if (e && e.__esModule) - return e; - const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } }); - if (e) { - for (const k in e) { - if (k !== 'default') { - const d = Object.getOwnPropertyDescriptor(e, k); - Object.defineProperty(n, k, d.get ? d : { - enumerable: true, - get: () => e[k] - }); - } - } - } - n.default = e; - return Object.freeze(n); - } - const React__namespace = /*#__PURE__*/ _interopNamespace(React); - var _path, _path2; - function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) { - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } - } return target; }; return _extends.apply(this, arguments); } - const SvgMenuBook = props => /*#__PURE__*/ React__namespace.createElement("svg", _extends({ - xmlns: "http://www.w3.org/2000/svg", - width: "1em", - height: "1em", - viewBox: "0 0 24 24", - role: "img", - stroke: "currentColor", - fill: "currentColor", - strokeWidth: "0" - }, props), _path || (_path = /*#__PURE__*/ React__namespace.createElement("path", { - d: "M17.5 4.5c-1.95 0-4.05.4-5.5 1.5-1.45-1.1-3.55-1.5-5.5-1.5-1.45 0-2.99.22-4.28.79C1.49 5.62 1 6.33 1 7.14v11.28c0 1.3 1.22 2.26 2.48 1.94.98-.25 2.02-.36 3.02-.36 1.56 0 3.22.26 4.56.92.6.3 1.28.3 1.87 0 1.34-.67 3-.92 4.56-.92 1 0 2.04.11 3.02.36 1.26.33 2.48-.63 2.48-1.94V7.14c0-.81-.49-1.52-1.22-1.85-1.28-.57-2.82-.79-4.27-.79zM21 17.23c0 .63-.58 1.09-1.2.98-.75-.14-1.53-.2-2.3-.2-1.7 0-4.15.65-5.5 1.5V8c1.35-.85 3.8-1.5 5.5-1.5.92 0 1.83.09 2.7.28.46.1.8.51.8.98v9.47z" - })), _path2 || (_path2 = /*#__PURE__*/ React__namespace.createElement("path", { - d: "M13.98 11.01c-.32 0-.61-.2-.71-.52-.13-.39.09-.82.48-.94 1.54-.5 3.53-.66 5.36-.45.41.05.71.42.66.83-.05.41-.42.71-.83.66-1.62-.19-3.39-.04-4.73.39-.08.01-.16.03-.23.03zm0 2.66c-.32 0-.61-.2-.71-.52-.13-.39.09-.82.48-.94 1.53-.5 3.53-.66 5.36-.45.41.05.71.42.66.83-.05.41-.42.71-.83.66-1.62-.19-3.39-.04-4.73.39a.97.97 0 0 1-.23.03zm0 2.66c-.32 0-.61-.2-.71-.52-.13-.39.09-.82.48-.94 1.53-.5 3.53-.66 5.36-.45.41.05.71.42.66.83-.05.41-.42.7-.83.66-1.62-.19-3.39-.04-4.73.39a.97.97 0 0 1-.23.03z" - }))); - /* eslint-disable no-undefined,no-param-reassign,no-shadow */ - /** - * Throttle execution of a function. Especially useful for rate limiting - * execution of handlers on events like resize and scroll. - * - * @param {number} delay - A zero-or-greater delay in milliseconds. For event callbacks, values around 100 or 250 (or even higher) - * are most useful. - * @param {Function} callback - A function to be executed after delay milliseconds. The \`this\` context and all arguments are passed through, - * as-is, to \`callback\` when the throttled-function is executed. - * @param {object} [options] - An object to configure options. - * @param {boolean} [options.noTrailing] - Optional, defaults to false. If noTrailing is true, callback will only execute every \`delay\` milliseconds - * while the throttled-function is being called. If noTrailing is false or unspecified, callback will be executed - * one final time after the last throttled-function call. (After the throttled-function has not been called for - * \`delay\` milliseconds, the internal counter is reset). - * @param {boolean} [options.noLeading] - Optional, defaults to false. If noLeading is false, the first throttled-function call will execute callback - * immediately. If noLeading is true, the first the callback execution will be skipped. It should be noted that - * callback will never executed if both noLeading = true and noTrailing = true. - * @param {boolean} [options.debounceMode] - If \`debounceMode\` is true (at begin), schedule \`clear\` to execute after \`delay\` ms. If \`debounceMode\` is - * false (at end), schedule \`callback\` to execute after \`delay\` ms. - * - * @returns {Function} A new, throttled, function. - */ - function throttle(delay, callback, options) { - var _ref = options || {}, _ref$noTrailing = _ref.noTrailing, noTrailing = _ref$noTrailing === void 0 ? false : _ref$noTrailing, _ref$noLeading = _ref.noLeading, noLeading = _ref$noLeading === void 0 ? false : _ref$noLeading, _ref$debounceMode = _ref.debounceMode, debounceMode = _ref$debounceMode === void 0 ? undefined : _ref$debounceMode; - /* - * After wrapper has stopped being called, this timeout ensures that - * \`callback\` is executed at the proper times in \`throttle\` and \`end\` - * debounce modes. - */ - var timeoutID; - var cancelled = false; // Keep track of the last time \`callback\` was executed. - var lastExec = 0; // Function to clear existing timeout - function clearExistingTimeout() { - if (timeoutID) { - clearTimeout(timeoutID); - } - } // Function to cancel next exec - function cancel(options) { - var _ref2 = options || {}, _ref2$upcomingOnly = _ref2.upcomingOnly, upcomingOnly = _ref2$upcomingOnly === void 0 ? false : _ref2$upcomingOnly; - clearExistingTimeout(); - cancelled = !upcomingOnly; - } - /* - * The \`wrapper\` function encapsulates all of the throttling / debouncing - * functionality and when executed will limit the rate at which \`callback\` - * is executed. - */ - function wrapper() { - for (var _len = arguments.length, arguments_ = new Array(_len), _key = 0; _key < _len; _key++) { - arguments_[_key] = arguments[_key]; - } - var self = this; - var elapsed = Date.now() - lastExec; - if (cancelled) { - return; - } // Execute \`callback\` and update the \`lastExec\` timestamp. - function exec() { - lastExec = Date.now(); - callback.apply(self, arguments_); - } - /* - * If \`debounceMode\` is true (at begin) this is used to clear the flag - * to allow future \`callback\` executions. - */ - function clear() { - timeoutID = undefined; - } - if (!noLeading && debounceMode && !timeoutID) { - /* - * Since \`wrapper\` is being called for the first time and - * \`debounceMode\` is true (at begin), execute \`callback\` - * and noLeading != true. - */ - exec(); - } - clearExistingTimeout(); - if (debounceMode === undefined && elapsed > delay) { - if (noLeading) { - /* - * In throttle mode with noLeading, if \`delay\` time has - * been exceeded, update \`lastExec\` and schedule \`callback\` - * to execute after \`delay\` ms. - */ - lastExec = Date.now(); - if (!noTrailing) { - timeoutID = setTimeout(debounceMode ? clear : exec, delay); - } - } - else { - /* - * In throttle mode without noLeading, if \`delay\` time has been exceeded, execute - * \`callback\`. - */ - exec(); - } - } - else if (noTrailing !== true) { - /* - * In trailing throttle mode, since \`delay\` time has not been - * exceeded, schedule \`callback\` to execute \`delay\` ms after most - * recent execution. - * - * If \`debounceMode\` is true (at begin), schedule \`clear\` to execute - * after \`delay\` ms. - * - * If \`debounceMode\` is false (at end), schedule \`callback\` to - * execute after \`delay\` ms. - */ - timeoutID = setTimeout(debounceMode ? clear : exec, debounceMode === undefined ? delay - elapsed : delay); - } - } - wrapper.cancel = cancel; // Return the wrapper function. - return wrapper; - } - const classes = { "fabRoot": "index-module_fabRoot__AUYw8", "fab": "index-module_fab__Uuak2", "progress": "index-module_progress__ffT7T", "popper": "index-module_popper__K0axO", "speedDial": "index-module_speedDial__RP62p", "speedDialItem": "index-module_speedDialItem__8j9Tj", "backdrop": "index-module_backdrop__IcRxK" }; - /** - * Fab 按钮 - */ - const Fab = ({ progress = 0, tip, speedDial, show: forceShow, initShow = true, autoTrans = false, focus, children, style, onClick, onBackdropClick, }) => { - // 上次滚动位置 - const lastY = React.useRef(window.pageYOffset); - const [show, setShow] = React.useState(initShow); - // 绑定滚动事件 - React.useEffect(() => { - window.addEventListener('scroll', throttle(200, (e) => { - // 跳过非用户操作的滚动 - if (e.isTrusted === false) - return; - if (window.pageYOffset === lastY.current) - return; - setShow( - // 滚动到底部时显示 - window.pageYOffset + window.innerHeight >= - document.body.scrollHeight || - // 向上滚动时显示,反之隐藏 - window.pageYOffset - lastY.current < 0); - lastY.current = window.pageYOffset; - })); - }, []); - // 将 forceShow 的变化同步到 show 上 - React.useEffect(() => { - if (forceShow) - setShow(forceShow); - }, [forceShow]); - const handleClick = React.useCallback(() => { - onClick?.(); - }, [onClick]); - const handleBackdropClick = React.useCallback(() => { - onBackdropClick?.(); - }, [onBackdropClick]); - return (jsxRuntime.jsxs("div", { className: classes.fabRoot, style: style, "data-show": forceShow ?? show, "data-trans": autoTrans, "data-focus": focus, children: [jsxRuntime.jsxs("button", { type: "button", className: classes.fab, onClick: handleClick, children: [children ?? jsxRuntime.jsx(SvgMenuBook, {}), jsxRuntime.jsx("span", { className: classes.progress, role: "progressbar", "aria-valuenow": progress, children: jsxRuntime.jsx("svg", { viewBox: "22 22 44 44", style: { strokeDashoffset: \`\${(1 - progress) * 290}%\` }, children: jsxRuntime.jsx("circle", { cx: "44", cy: "44", r: "20.2", fill: "none", strokeWidth: "3.6" }) }) }), tip ? jsxRuntime.jsx("div", { className: classes.popper, children: tip }) : null] }), speedDial?.length ? (jsxRuntime.jsxs("div", { className: classes.speedDial, children: [jsxRuntime.jsx("div", { className: classes.backdrop, onClick: handleBackdropClick }), speedDial?.map((SpeedDialItem, i) => (jsxRuntime.jsx("div", { className: classes.speedDialItem, style: { - '--show-delay': \`\${i * 30}ms\`, - '--hide-delay': \`\${(speedDial.length - 1 - i) * 50}ms\`, - }, "data-i": i * 30, children: jsxRuntime.jsx(SpeedDialItem, {}) }, i)))] })) : null] })); - }; - exports.Fab = Fab; - }; - const selfModule = module.exports; - module.exports = new Proxy(selfModule, { - get(_, prop) { - if (selfModule[prop] === undefined) - main(); - return selfModule[prop]; - }, - apply(_, __, args) { - if (selfModule[prop] === undefined) - main(); - return selfModule[prop](...args); - }, - construct(_, args) { - if (selfModule[prop] === undefined) - main(); - return new selfModule[prop](...args); - }, - }); -}(Fab, Fab.exports)); - -const FabStyle = ".index-module_fabRoot__AUYw8{font-size:1.1em;transition:transform .2s}.index-module_fabRoot__AUYw8[data-show=false]{transform:scale(0)}.index-module_fabRoot__AUYw8[data-trans=true]{opacity:.8}.index-module_fabRoot__AUYw8[data-trans=true]:focus,.index-module_fabRoot__AUYw8[data-trans=true]:hover{opacity:1}.index-module_fab__Uuak2{align-items:center;background-color:var(--fab,#607d8b);border:none;border-radius:100%;box-shadow:0 3px 5px -1px #0003,0 6px 10px 0 #00000024,0 1px 18px 0 #0000001f;color:#fff;cursor:pointer;display:flex;font-size:1em;height:3.6em;justify-content:center;width:3.6em}.index-module_fab__Uuak2>svg{font-size:1.5em}.index-module_fab__Uuak2:hover{background-color:var(--fab_hover,#78909c)}.index-module_progress__ffT7T{color:#b0bec5;display:inline-block;height:100%;position:absolute;transform:rotate(-90deg);transition:transform .3s cubic-bezier(.4,0,.2,1) 0ms;width:100%}.index-module_progress__ffT7T>svg{stroke:currentcolor;stroke-dasharray:290%;stroke-dashoffset:100%;stroke-linecap:round;transition:stroke-dashoffset .3s cubic-bezier(.4,0,.2,1) 0ms}.index-module_progress__ffT7T:hover{color:#cfd8dc}.index-module_progress__ffT7T[aria-valuenow=\\"1\\"]{opacity:0;transition:opacity .2s .15s}.index-module_popper__K0axO{align-items:center;background-color:#303030;border-radius:.3em;color:#fff;display:none;font-size:.8em;padding:.4em .5em;position:absolute;right:calc(100% + 1.5em);top:50%;transform:translateY(-50%);white-space:nowrap}:is(.index-module_fab__Uuak2:hover,.index-module_fabRoot__AUYw8[data-focus=true]) .index-module_popper__K0axO{display:flex}.index-module_speedDial__RP62p{align-items:center;bottom:0;display:flex;flex-direction:column-reverse;font-size:1.1em;padding-bottom:120%;pointer-events:none;position:absolute;width:100%;z-index:-1}.index-module_speedDialItem__8j9Tj{margin:.1em 0;opacity:0;transform:scale(0);transition-delay:var(--hide-delay);transition-duration:.23s;transition-property:transform,opacity}.index-module_speedDial__RP62p:hover,:is(.index-module_fabRoot__AUYw8:hover,.index-module_fabRoot__AUYw8[data-focus=true])>.index-module_speedDial__RP62p{pointer-events:all}:is(.index-module_fabRoot__AUYw8:hover,.index-module_fabRoot__AUYw8[data-focus=true])>.index-module_speedDial__RP62p>.index-module_speedDialItem__8j9Tj{opacity:unset;transform:unset;transition-delay:var(--show-delay)}.index-module_backdrop__IcRxK{background:#000;height:100vh;left:0;opacity:0;pointer-events:none;position:fixed;top:0;transition:opacity .5s;width:100vw}:is(.index-module_fabRoot__AUYw8:hover,.index-module_fabRoot__AUYw8[data-focus=true],.index-module_speedDial__RP62p:hover) .index-module_backdrop__IcRxK{opacity:.4}.index-module_fabRoot__AUYw8[data-focus=true] .index-module_backdrop__IcRxK{pointer-events:unset}"; - -const useFab = async (initProps) => { - const [root] = useComponentsRoot('fab'); - await GM.addStyle(\` - #fab > div { - --text_bg: transparent; - - position: fixed; - z-index: 999999999; - right: 3vw; - bottom: 6vh; - - font-size: clamp(12px, 1.5vw, 16px); - } - \`); - const props = { ...initProps }; - const FabIcon = () => { - switch (props.progress) { - case undefined: - // 没有内容的书 - return require$$0.jsx(SvgImportContacts, {}); - case 1: - case 2: - // 有内容的书 - return require$$0.jsx(SvgMenuBook, {}); - default: - return props.progress > 1 ? require$$0.jsx(SvgCloudDownload, {}) : require$$0.jsx(SvgImageSearch, {}); - } - }; - const set = (recipe) => { - if (recipe) { - Object.assign(props, typeof recipe === 'function' ? recipe(props) : recipe); - } - root.render(require$$0.jsxs(shadow__default.default.div, { children: [require$$0.jsx(Fab.exports.Fab, { ...props, children: props.children ?? require$$0.jsx(FabIcon, {}) }), require$$0.jsx("style", { type: "text/css", children: IconBottonStyle }), require$$0.jsx("style", { type: "text/css", children: FabStyle })] })); - }; - return set; -}; - -/** - * 对修改站点配置的相关方法的封装 - * - * @param name 站点名 - * @param defaultOptions 默认配置 - */ -const useSiteOptions = async (name, defaultOptions = {}) => { - const rawValue = await GM.getValue(name); - const options = Object.assign({ - option: undefined, - autoShow: true, - hiddenFAB: false, - ...defaultOptions, - }, rawValue); - const changeCallbackList = []; - return { - options, - /** 该站点是否有储存配置 */ - isRecorded: rawValue !== undefined, - /** - * 设置新 Option - * - * @param newValue newValue - * @param trigger 是否触发变更事件 - */ - setOptions: async (newValue, trigger = true) => { - Object.assign(options, newValue); - await GM.setValue(name, options); - if (trigger) - await Promise.all(changeCallbackList.map((callback) => callback(options))); - }, - /** - * 监听配置变更事件 - */ - onOptionChange: (callback) => { - changeCallbackList.push(callback); - }, - }; -}; - -/* eslint-disable import/no-cycle */ -/** - * 对三个样式组件和 useSiteOptions 的默认值进行封装 - * - * @param name 站点名 - * @param defaultOptions 默认配置 - */ -const useInit = async (name, defaultOptions = {}) => { - const { options, setOptions, onOptionChange } = await useSiteOptions(name, defaultOptions); - const setFab = await useFab({ - tip: '阅读模式', - speedDial: defaultSpeedDial(options, setOptions), - }); - onOptionChange(() => setFab()); - const [setManga, mangaProps] = await useManga({ - imgList: [], - option: options.option, - onOptionChange: (option) => setOptions({ ...options, option }), - }); - const toast = useToast(); - // 检查脚本的版本变化,提示用户 - const version = await GM.getValue('Version'); - if (version && version !== GM.info.script.version) { - // FIXME: 实现通过 jsdelivr 获取指定版本的更新内容 - // const changelog = \` - // ## 新增 - // - 通过 M 键切换页面填充 - // ## 修复 - // - 增加拷贝漫画的支持域名 - // - 修复漫画柜失效问题 - // \`; - (async () => { - // const res = await request( - // \`https://cdn.jsdelivr.net/gh/hymbz/ComicReadScriptTest@\${GM.info.script.version}/file\`, - // { errorText: '' }, - // ); - // toast(() => ( - //
- //

ComicReadScrip 已更新到 {GM.info.script.version}

- //
- // {res.responseText.match(/##.+?\\n|(-.+?\\n)+/g)!.map((mdText) => { - // if (mdText[0] === '#') return

{mdText.split('##')}

; - // if (mdText[0] === '-') - // return ( - //
    - // {mdText.match(/(?<=- ).+/g)!.map((item) => ( - //
  • {item}
  • - // ))} - //
- // ); - // return null; - // })} - //
- //
- // )); - // GM_setValue('Version', GM.info.script.version); - })(); - } - let menuId; - /** 更新显示/隐藏阅读模式按钮的菜单项 */ - const updateHideFabMenu = async () => { - await GM.unregisterMenuCommand(menuId); - menuId = await GM.registerMenuCommand(\`\${options.hiddenFAB ? '显示' : '隐藏'}阅读模式按钮\`, async () => { - await setOptions({ ...options, hiddenFAB: !options.hiddenFAB }); - setFab((draftProps) => { - draftProps.show = !options.hiddenFAB && undefined; - }); - await updateHideFabMenu(); - }); - }; - return { - options, - setOptions, - onOptionChange, - setFab, - setManga, - toast, - /** - * 完成所有支持站点的初始化 - * - * @param getImgList 返回图片列表的函数 - * @param onLoading 图片加载状态发生变化时触发的回调 - * @returns 自动加载图片并进入阅读模式的函数 - */ - init: (getImgList, onLoading = () => { }) => { - /** 是否正在加载图片中 */ - let loading = false; - /** 进入阅读模式 */ - const showComic = async (show = options.autoShow) => { - if (loading) { - toast('加载图片中,请稍候', { autoClose: 1500 }); - return; - } - const { imgList } = mangaProps; - if (!imgList.length) { - loading = true; - try { - setFab({ progress: 0, show: true }); - const initImgList = await getImgList(); - if (initImgList.length === 0) - throw new Error('获取漫画图片失败'); - setFab({ - progress: 1, - tip: '阅读模式', - show: !options.hiddenFAB && undefined, - }); - setManga((draftProps) => { - draftProps.imgList = initImgList; - draftProps.show = show; - setToolbarButton(draftProps); - // 监听图片加载状态,将进度显示到 Fab 上 - draftProps.onLoading = (img, list) => { - const loadNum = list.filter((image) => image.loadType === 'loaded').length; - onLoading(loadNum, list.length, img); - /** 图片加载进度 */ - const progress = 1 + loadNum / list.length; - if (progress !== 2) { - setFab({ - progress, - tip: \`图片加载中 - \${loadNum}/\${list.length}\`, - }); - } - else { - // 图片全部加载完成后恢复 Fab 状态 - setFab({ progress, tip: '阅读模式', show: undefined }); - } - }; - return draftProps; - }); - } - catch (e) { - console.error(e); - toast.error(e.message); - setFab({ progress: undefined }); - } - finally { - loading = false; - } - } - else { - setManga({ show: true }); - } - }; - setFab({ onClick: () => showComic(true) }); - // eslint-disable-next-line @typescript-eslint/no-floating-promises - if (options.autoShow) - showComic(); - // eslint-disable-next-line @typescript-eslint/no-floating-promises - GM.registerMenuCommand('进入漫画阅读模式', () => showComic(true)); - // eslint-disable-next-line @typescript-eslint/no-floating-promises - updateHideFabMenu(); - return () => showComic(true); - }, - }; -}; - -exports.dataToParams = dataToParams; -exports.defaultSpeedDial = defaultSpeedDial; -exports.insertNode = insertNode; -exports.isEqualArray = isEqualArray; -exports.linstenKeyup = linstenKeyup; -exports.plimit = plimit; -exports.promisifyRequest = promisifyRequest; -exports.querySelector = querySelector; -exports.querySelectorAll = querySelectorAll; -exports.querySelectorClick = querySelectorClick; -exports.request = request; -exports.saveAs = saveAs; -exports.scrollIntoView = scrollIntoView; -exports.setToolbarButton = setToolbarButton; -exports.sleep = sleep; -exports.useCache = useCache; -exports.useComponentsRoot = useComponentsRoot; -exports.useFab = useFab; -exports.useInit = useInit; -exports.useManga = useManga; -exports.useSiteOptions = useSiteOptions; -exports.useToast = useToast; -`; - -unsafeWindow.crsLib = { - // 有些 cjs 模块会检查这个,所以在这里声明下 - process: { env: { NODE_ENV: 'production' } }, - // 把 GM 相关函数放进去以便其中使用 - GM, - GM_xmlhttpRequest, -}; -/** - * 通过 Resource 导入外部模块 - * - * @param name \@resource 引用的资源名 - */ -const selfImportSync = (name) => { - const code = name === '../helper' ? helperCode : GM_getResourceText(name); - if (!code) throw new Error(`外部模块 ${name} 未在 @Resource 中声明`); - // 通过提供 cjs 环境的变量来欺骗 umd 模块加载器 - // 将模块导出变量放到 crsLib 对象里,防止污染全局作用域和网站自身的模块产生冲突 - return GM_addElement('script', { - textContent: ` - window.crsLib['${name}'] = {}; - ${''} - (function (process, require, exports, module, GM, GM_xmlhttpRequest) { - ${code} - })( - window.crsLib.process, - window.crsLib.require, - window.crsLib['${name}'], - { - set exports(value) { - window.crsLib['${name}'] = value; - }, - get exports() { - return window.crsLib['${name}']; - }, - }, - window.crsLib.GM, - window.crsLib.GM_xmlhttpRequest, - ); - ${''} - `, - }); -}; -/** - * 创建一个外部模块的 Proxy,等到读取对象属性时才加载模块 - * - * @param name 外部模块名 - */ -const require = (name) => { - // 为了应对 rollup 打包时的工具函数 _interopNamespace,要给外部库加上 __esModule 标志 - const __esModule = { value: true }; - // rollup 打包后的代码里有时候会先把 default 单独抽出来之后再使用,所以也要把 default 改成动态加载 - const selfDefault = new Proxy(function selfLibProxy() {}, { - get(_, prop) { - if (prop === '__esModule') return __esModule; - if (!unsafeWindow.crsLib[name]) selfImportSync(name); - const module = unsafeWindow.crsLib[name]; - return module.default?.[prop] ?? module?.[prop]; - }, - apply(_, __, args) { - if (!unsafeWindow.crsLib[name]) selfImportSync(name); - const module = unsafeWindow.crsLib[name]; - const ModuleFunc = - typeof module.default === 'function' ? module.default : module; - return ModuleFunc(...args); - }, - construct(_, args) { - if (!unsafeWindow.crsLib[name]) selfImportSync(name); - const module = unsafeWindow.crsLib[name]; - const ModuleFunc = - typeof module.default === 'function' ? module.default : module; - return new ModuleFunc(...args); - }, - }); - return new Proxy( - { default: selfDefault }, - { - get(_, prop) { - if (prop === 'default') return _.default; - if (prop === '__esModule') return __esModule; - if (!unsafeWindow.crsLib[name]) selfImportSync(name); - const module = unsafeWindow.crsLib[name]; - return module[prop]; - }, - }, - ); -}; -unsafeWindow.crsLib.require = require; - -// 匹配站点 -switch (window.location.hostname) { - case 'bbs.yamibo.com': { - const jsxRuntime = require('react/jsx-runtime'); - const React = require('react'); - const helper = require('../helper'); - - function _interopNamespace(e) { - if (e && e.__esModule) return e; - const n = Object.create(null, { - [Symbol.toStringTag]: { value: 'Module' }, - }); - if (e) { - for (const k in e) { - if (k !== 'default') { - const d = Object.getOwnPropertyDescriptor(e, k); - Object.defineProperty( - n, - k, - d.get - ? d - : { - enumerable: true, - get: () => e[k], - }, - ); - } - } - } - n.default = e; - return Object.freeze(n); - } - - const React__namespace = /*#__PURE__*/ _interopNamespace(React); - - var _path; - function _extends() { - _extends = Object.assign - ? Object.assign.bind() - : function (target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - for (var key in source) { - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } - } - return target; - }; - return _extends.apply(this, arguments); - } - const SvgSettings = (props) => - /*#__PURE__*/ React__namespace.createElement( - 'svg', - _extends( - { - xmlns: 'http://www.w3.org/2000/svg', - width: '1em', - height: '1em', - viewBox: '0 0 24 24', - role: 'img', - stroke: 'currentColor', - fill: 'currentColor', - strokeWidth: '0', - }, - props, - ), - _path || - (_path = /*#__PURE__*/ React__namespace.createElement('path', { - d: 'M19.5 12c0-.23-.01-.45-.03-.68l1.86-1.41c.4-.3.51-.86.26-1.3l-1.87-3.23a.987.987 0 0 0-1.25-.42l-2.15.91c-.37-.26-.76-.49-1.17-.68l-.29-2.31c-.06-.5-.49-.88-.99-.88h-3.73c-.51 0-.94.38-1 .88l-.29 2.31c-.41.19-.8.42-1.17.68l-2.15-.91c-.46-.2-1-.02-1.25.42L2.41 8.62c-.25.44-.14.99.26 1.3l1.86 1.41a7.343 7.343 0 0 0 0 1.35l-1.86 1.41c-.4.3-.51.86-.26 1.3l1.87 3.23c.25.44.79.62 1.25.42l2.15-.91c.37.26.76.49 1.17.68l.29 2.31c.06.5.49.88.99.88h3.73c.5 0 .93-.38.99-.88l.29-2.31c.41-.19.8-.42 1.17-.68l2.15.91c.46.2 1 .02 1.25-.42l1.87-3.23c.25-.44.14-.99-.26-1.3l-1.86-1.41c.03-.23.04-.45.04-.68zm-7.46 3.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z', - })), - ); - - /** 签到按钮的选择器 */ - const checkInDomSelectors = - '.header-tool > li > a[href^="plugin.php?id=study_daily_attendance"]'; - (async () => { - const { options, setFab, setManga, init } = await helper.useInit( - 'yamibo', - { - 记录阅读进度: true, - 关闭快捷导航按钮的跳转: true, - 修正点击页数时的跳转判定: true, - 固定导航条: true, - 自动签到: true, - }, - ); - await GM.addStyle(`#fab { --fab: #6E2B19; --fab_hover: #A15640; }; - - ${ - options.固定导航条 ? '.header-stackup { position: fixed !important }' : '' - } - - .historyTag { - white-space: nowrap; - - border: 2px solid #6e2b19; - } - - a.historyTag { - font-weight: bold; - - margin-left: 1em; - padding: 1px 4px; - - color: #6e2b19; - border-radius: 4px 0 0 4px; - } - a.historyTag:last-child { - border-radius: 4px; - } - - div.historyTag { - display: initial; - - margin-left: -.4em; - padding: 1px; - - color: RGB(255, 237, 187); - border-radius: 0 4px 4px 0; - background-color: #6e2b19; - } - - #threadlisttableid tbody:nth-child(2n) div.historyTag { - color: RGB(255, 246, 215); - } - - /* 隐藏签到按钮 */ - ${checkInDomSelectors} { - display: none; - } - - /* 将「回复/查看」列加宽一点 */ - .tl .num { - width: 80px !important; - } - `); - // 自动签到 - if (options.自动签到) { - const checkInDom = helper.querySelector(checkInDomSelectors); - // eslint-disable-next-line @typescript-eslint/no-floating-promises - if (checkInDom) fetch(checkInDom.href); - } - if (options.关闭快捷导航按钮的跳转) - // eslint-disable-next-line no-script-url - helper.querySelector('#qmenu a')?.setAttribute('href', 'javascript:;'); - // 增加菜单项,以便在其他板块用于调整其他功能的开关 - await GM.registerMenuCommand('显示设置菜单', () => - setFab({ - show: true, - focus: true, - tip: '设置', - children: jsxRuntime.jsx(SvgSettings, {}), - onBackdropClick: () => setFab({ show: false, focus: false }), - }), - ); - // 判断当前页是帖子 - if (/thread(-\d+){3}|mod=viewthread/.test(document.URL)) { - // 修复微博图床的链接 - helper.querySelectorAll('img[file*="sinaimg.cn"]').forEach((e) => { - e.setAttribute('referrerpolicy', 'no-referrer'); - }); - if ( - // 限定板块启用 - (fid === 30 || fid === 37) && - // 只在第一页生效 - !helper.querySelector('.pg > .prev') - ) { - let imgList = helper.querySelectorAll('.t_fsz img'); - const updateImgList = () => { - let i = imgList.length; - while (i--) { - const img = imgList[i]; - const file = img.getAttribute('file'); - if (file && img.src !== file) { - img.setAttribute('src', file); - img.setAttribute('lazyloaded', 'true'); - } - // 测试例子:https://bbs.yamibo.com/thread-502399-1-1.html - // 删掉表情和小图 - if ( - img.src.includes('static/image') || - (img.complete && - img.naturalHeight && - img.naturalWidth && - img.naturalHeight < 500 && - img.naturalWidth < 500) - ) - imgList.splice(i, 1); - } - return imgList.map((img) => img.src); - }; - setManga({ - // 在图片加载完成后再检查一遍有没有小图,有就删掉 - onLoading: (img) => { - // 跳过符合标准的 - if ( - img.height && - img.width && - img.height > 500 && - img.width > 500 - ) - return; - const delImgIndex = imgList.findIndex( - (image) => image.src === img.src, - ); - if (delImgIndex !== -1) imgList.splice(delImgIndex, 1); - setManga({ imgList: imgList.map((image) => image.src) }); - }, - onExit: (isEnd) => { - if (isEnd) - helper.scrollIntoView( - '.psth, .rate, #postlist > div:nth-of-type(2)', - ); - setManga({ show: false }); - }, - }); - updateImgList(); - const showComic = init(() => imgList.map((img) => img.src)); - setFab({ progress: 1, tip: '阅读模式' }); - // 虽然有 Fab 了不需要这个按钮,但都点习惯了没有还挺别扭的( - helper.insertNode( - helper.querySelector('div.pti > div.authi'), - '|漫画阅读', - ); - document - .getElementById('comicReadMode') - ?.addEventListener('click', showComic); - // 如果帖子内有设置目录 - if (helper.querySelector('#threadindex')) { - helper.querySelectorAll('#threadindex li').forEach((dom) => { - dom.addEventListener('click', () => { - setTimeout(() => { - imgList = helper.querySelectorAll('.t_fsz img'); - setManga({ - imgList: updateImgList(), - show: options.autoShow ?? undefined, - }); - }, 1000); - }); - }); - } - const tagDom = helper.querySelector('.ptg.mbm.mtn > a'); - // 通过标签确定上/下一话 - if (tagDom) { - const tagId = tagDom.href.split('id=')[1]; - const reg = /(?<=\s - 回第${data.lastPageNum}页 - - ${ - lastReplies > 0 - ? `
+${lastReplies}
` - : '' - } - `, - ); - }), - ); - }; - // eslint-disable-next-line @typescript-eslint/no-floating-promises - updateHistoryTag(); - // 切换回当前页时更新提示 - document.addEventListener('visibilitychange', updateHistoryTag); - // 点击下一页后更新提示 - helper - .querySelector('#autopbn') - .addEventListener('click', updateHistoryTag); - } - } - })(); - - break; - } - case 'www.yamibo.com': { - const helper = require('../helper'); - - (async () => { - // 只在漫画页内运行 - if (!document.URL.includes('view-chapter')) return; - const { setFab, setManga, init } = await helper.useInit('newYamibo'); - setManga({ - onNext: helper.querySelectorClick('#btnNext'), - onPrev: helper.querySelectorClick('#btnPrev'), - onExit: (isEnd) => { - if (isEnd) helper.scrollIntoView('#w1'); - setManga({ show: false }); - }, - }); - const id = new URLSearchParams(window.location.search).get('id'); - /** 总页数 */ - const totalNum = +helper - .querySelector('section div:first-of-type div:last-of-type') - .innerHTML.split(':')[1]; - const getImgList = async (i = 1, imgList = []) => { - const res = await helper.request( - `https://www.yamibo.com/manga/view-chapter?id=${id}&page=${i}`, - ); - imgList.push( - // - .exec(res.responseText)[1] - .replaceAll('&', '&'), - ); - if (imgList.length === totalNum) { - setFab({ progress: 1, tip: '阅读模式' }); - return imgList; - } - setFab({ - progress: imgList.length / totalNum, - tip: `加载图片中 - ${imgList.length}/${totalNum}`, - }); - return getImgList(i + 1, imgList); - }; - init(getImgList); - })(); - - break; - } - - case 'manhua.idmzj.com': - case 'manhua.dmzj.com': { - const helper = require('../helper'); - const jsxRuntime = require('react/jsx-runtime'); - const shadow = require('react-shadow'); - const reactToastify = require('react-toastify'); - - const _interopDefaultLegacy = (e) => - e && typeof e === 'object' && 'default' in e ? e : { default: e }; - - const shadow__default = /*#__PURE__*/ _interopDefaultLegacy(shadow); - - const ToastStyle = - ':root{--toastify-color-light:#fff;--toastify-color-dark:#121212;--toastify-color-info:#3498db;--toastify-color-success:#07bc0c;--toastify-color-warning:#f1c40f;--toastify-color-error:#e74c3c;--toastify-color-transparent:hsla(0,0%,100%,.7);--toastify-icon-color-info:var(--toastify-color-info);--toastify-icon-color-success:var(--toastify-color-success);--toastify-icon-color-warning:var(--toastify-color-warning);--toastify-icon-color-error:var(--toastify-color-error);--toastify-toast-width:320px;--toastify-toast-background:#fff;--toastify-toast-min-height:64px;--toastify-toast-max-height:800px;--toastify-font-family:sans-serif;--toastify-z-index:9999;--toastify-text-color-light:#757575;--toastify-text-color-dark:#fff;--toastify-text-color-info:#fff;--toastify-text-color-success:#fff;--toastify-text-color-warning:#fff;--toastify-text-color-error:#fff;--toastify-spinner-color:#616161;--toastify-spinner-color-empty-area:#e0e0e0;--toastify-color-progress-light:linear-gradient(90deg,#4cd964,#5ac8fa,#007aff,#34aadc,#5856d6,#ff2d55);--toastify-color-progress-dark:#bb86fc;--toastify-color-progress-info:var(--toastify-color-info);--toastify-color-progress-success:var(--toastify-color-success);--toastify-color-progress-warning:var(--toastify-color-warning);--toastify-color-progress-error:var(--toastify-color-error)}.Toastify__toast-container{z-index:var(--toastify-z-index);-webkit-transform:translateZ(var(--toastify-z-index));position:fixed;padding:4px;width:var(--toastify-toast-width);box-sizing:border-box;color:#fff}.Toastify__toast-container--top-left{top:1em;left:1em}.Toastify__toast-container--top-center{top:1em;left:50%;transform:translateX(-50%)}.Toastify__toast-container--top-right{top:1em;right:1em}.Toastify__toast-container--bottom-left{bottom:1em;left:1em}.Toastify__toast-container--bottom-center{bottom:1em;left:50%;transform:translateX(-50%)}.Toastify__toast-container--bottom-right{bottom:1em;right:1em}@media only screen and (max-width:480px){.Toastify__toast-container{width:100vw;padding:0;left:0;margin:0}.Toastify__toast-container--top-center,.Toastify__toast-container--top-left,.Toastify__toast-container--top-right{top:0;transform:translateX(0)}.Toastify__toast-container--bottom-center,.Toastify__toast-container--bottom-left,.Toastify__toast-container--bottom-right{bottom:0;transform:translateX(0)}.Toastify__toast-container--rtl{right:0;left:auto}}.Toastify__toast{position:relative;min-height:var(--toastify-toast-min-height);box-sizing:border-box;margin-bottom:1rem;padding:8px;border-radius:4px;box-shadow:0 1px 10px 0 rgba(0,0,0,.1),0 2px 15px 0 rgba(0,0,0,.05);display:-ms-flexbox;display:flex;-ms-flex-pack:justify;justify-content:space-between;max-height:var(--toastify-toast-max-height);overflow:hidden;font-family:var(--toastify-font-family);cursor:pointer;direction:ltr;z-index:0}.Toastify__toast--rtl{direction:rtl}.Toastify__toast-body{margin:auto 0;-ms-flex:1 1 auto;flex:1 1 auto;padding:6px;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.Toastify__toast-body>div:last-child{-ms-flex:1;flex:1}.Toastify__toast-icon{-webkit-margin-end:10px;margin-inline-end:10px;width:20px;-ms-flex-negative:0;flex-shrink:0;display:-ms-flexbox;display:flex}.Toastify--animate{animation-fill-mode:both;animation-duration:.7s}.Toastify--animate-icon{animation-fill-mode:both;animation-duration:.3s}@media only screen and (max-width:480px){.Toastify__toast{margin-bottom:0;border-radius:0}}.Toastify__toast-theme--dark{background:var(--toastify-color-dark);color:var(--toastify-text-color-dark)}.Toastify__toast-theme--colored.Toastify__toast--default,.Toastify__toast-theme--light{background:var(--toastify-color-light);color:var(--toastify-text-color-light)}.Toastify__toast-theme--colored.Toastify__toast--info{color:var(--toastify-text-color-info);background:var(--toastify-color-info)}.Toastify__toast-theme--colored.Toastify__toast--success{color:var(--toastify-text-color-success);background:var(--toastify-color-success)}.Toastify__toast-theme--colored.Toastify__toast--warning{color:var(--toastify-text-color-warning);background:var(--toastify-color-warning)}.Toastify__toast-theme--colored.Toastify__toast--error{color:var(--toastify-text-color-error);background:var(--toastify-color-error)}.Toastify__progress-bar-theme--light{background:var(--toastify-color-progress-light)}.Toastify__progress-bar-theme--dark{background:var(--toastify-color-progress-dark)}.Toastify__progress-bar--info{background:var(--toastify-color-progress-info)}.Toastify__progress-bar--success{background:var(--toastify-color-progress-success)}.Toastify__progress-bar--warning{background:var(--toastify-color-progress-warning)}.Toastify__progress-bar--error{background:var(--toastify-color-progress-error)}.Toastify__progress-bar-theme--colored.Toastify__progress-bar--error,.Toastify__progress-bar-theme--colored.Toastify__progress-bar--info,.Toastify__progress-bar-theme--colored.Toastify__progress-bar--success,.Toastify__progress-bar-theme--colored.Toastify__progress-bar--warning{background:var(--toastify-color-transparent)}.Toastify__close-button{color:#fff;background:transparent;outline:none;border:none;padding:0;cursor:pointer;opacity:.7;transition:.3s ease;-ms-flex-item-align:start;align-self:flex-start}.Toastify__close-button--light{color:#000;opacity:.3}.Toastify__close-button>svg{fill:currentColor;height:16px;width:14px}.Toastify__close-button:focus,.Toastify__close-button:hover{opacity:1}@keyframes Toastify__trackProgress{0%{transform:scaleX(1)}to{transform:scaleX(0)}}.Toastify__progress-bar{position:absolute;bottom:0;left:0;width:100%;height:5px;z-index:var(--toastify-z-index);opacity:.7;transform-origin:left}.Toastify__progress-bar--animated{animation:Toastify__trackProgress linear 1 forwards}.Toastify__progress-bar--controlled{transition:transform .2s}.Toastify__progress-bar--rtl{right:0;left:auto;transform-origin:right}.Toastify__spinner{width:20px;height:20px;box-sizing:border-box;border:2px solid;border-radius:100%;border-color:var(--toastify-spinner-color-empty-area);border-right-color:var(--toastify-spinner-color);animation:Toastify__spin .65s linear infinite}@keyframes Toastify__bounceInRight{0%,60%,75%,90%,to{animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;transform:translate3d(3000px,0,0)}60%{opacity:1;transform:translate3d(-25px,0,0)}75%{transform:translate3d(10px,0,0)}90%{transform:translate3d(-5px,0,0)}to{transform:none}}@keyframes Toastify__bounceOutRight{20%{opacity:1;transform:translate3d(-20px,0,0)}to{opacity:0;transform:translate3d(2000px,0,0)}}@keyframes Toastify__bounceInLeft{0%,60%,75%,90%,to{animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;transform:translate3d(-3000px,0,0)}60%{opacity:1;transform:translate3d(25px,0,0)}75%{transform:translate3d(-10px,0,0)}90%{transform:translate3d(5px,0,0)}to{transform:none}}@keyframes Toastify__bounceOutLeft{20%{opacity:1;transform:translate3d(20px,0,0)}to{opacity:0;transform:translate3d(-2000px,0,0)}}@keyframes Toastify__bounceInUp{0%,60%,75%,90%,to{animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;transform:translate3d(0,3000px,0)}60%{opacity:1;transform:translate3d(0,-20px,0)}75%{transform:translate3d(0,10px,0)}90%{transform:translate3d(0,-5px,0)}to{transform:translateZ(0)}}@keyframes Toastify__bounceOutUp{20%{transform:translate3d(0,-10px,0)}40%,45%{opacity:1;transform:translate3d(0,20px,0)}to{opacity:0;transform:translate3d(0,-2000px,0)}}@keyframes Toastify__bounceInDown{0%,60%,75%,90%,to{animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;transform:translate3d(0,-3000px,0)}60%{opacity:1;transform:translate3d(0,25px,0)}75%{transform:translate3d(0,-10px,0)}90%{transform:translate3d(0,5px,0)}to{transform:none}}@keyframes Toastify__bounceOutDown{20%{transform:translate3d(0,10px,0)}40%,45%{opacity:1;transform:translate3d(0,-20px,0)}to{opacity:0;transform:translate3d(0,2000px,0)}}.Toastify__bounce-enter--bottom-left,.Toastify__bounce-enter--top-left{animation-name:Toastify__bounceInLeft}.Toastify__bounce-enter--bottom-right,.Toastify__bounce-enter--top-right{animation-name:Toastify__bounceInRight}.Toastify__bounce-enter--top-center{animation-name:Toastify__bounceInDown}.Toastify__bounce-enter--bottom-center{animation-name:Toastify__bounceInUp}.Toastify__bounce-exit--bottom-left,.Toastify__bounce-exit--top-left{animation-name:Toastify__bounceOutLeft}.Toastify__bounce-exit--bottom-right,.Toastify__bounce-exit--top-right{animation-name:Toastify__bounceOutRight}.Toastify__bounce-exit--top-center{animation-name:Toastify__bounceOutUp}.Toastify__bounce-exit--bottom-center{animation-name:Toastify__bounceOutDown}@keyframes Toastify__zoomIn{0%{opacity:0;transform:scale3d(.3,.3,.3)}50%{opacity:1}}@keyframes Toastify__zoomOut{0%{opacity:1}50%{opacity:0;transform:scale3d(.3,.3,.3)}to{opacity:0}}.Toastify__zoom-enter{animation-name:Toastify__zoomIn}.Toastify__zoom-exit{animation-name:Toastify__zoomOut}@keyframes Toastify__flipIn{0%{transform:perspective(400px) rotateX(90deg);animation-timing-function:ease-in;opacity:0}40%{transform:perspective(400px) rotateX(-20deg);animation-timing-function:ease-in}60%{transform:perspective(400px) rotateX(10deg);opacity:1}80%{transform:perspective(400px) rotateX(-5deg)}to{transform:perspective(400px)}}@keyframes Toastify__flipOut{0%{transform:perspective(400px)}30%{transform:perspective(400px) rotateX(-20deg);opacity:1}to{transform:perspective(400px) rotateX(90deg);opacity:0}}.Toastify__flip-enter{animation-name:Toastify__flipIn}.Toastify__flip-exit{animation-name:Toastify__flipOut}@keyframes Toastify__slideInRight{0%{transform:translate3d(110%,0,0);visibility:visible}to{transform:translateZ(0)}}@keyframes Toastify__slideInLeft{0%{transform:translate3d(-110%,0,0);visibility:visible}to{transform:translateZ(0)}}@keyframes Toastify__slideInUp{0%{transform:translate3d(0,110%,0);visibility:visible}to{transform:translateZ(0)}}@keyframes Toastify__slideInDown{0%{transform:translate3d(0,-110%,0);visibility:visible}to{transform:translateZ(0)}}@keyframes Toastify__slideOutRight{0%{transform:translateZ(0)}to{visibility:hidden;transform:translate3d(110%,0,0)}}@keyframes Toastify__slideOutLeft{0%{transform:translateZ(0)}to{visibility:hidden;transform:translate3d(-110%,0,0)}}@keyframes Toastify__slideOutDown{0%{transform:translateZ(0)}to{visibility:hidden;transform:translate3d(0,500px,0)}}@keyframes Toastify__slideOutUp{0%{transform:translateZ(0)}to{visibility:hidden;transform:translate3d(0,-500px,0)}}.Toastify__slide-enter--bottom-left,.Toastify__slide-enter--top-left{animation-name:Toastify__slideInLeft}.Toastify__slide-enter--bottom-right,.Toastify__slide-enter--top-right{animation-name:Toastify__slideInRight}.Toastify__slide-enter--top-center{animation-name:Toastify__slideInDown}.Toastify__slide-enter--bottom-center{animation-name:Toastify__slideInUp}.Toastify__slide-exit--bottom-left,.Toastify__slide-exit--top-left{animation-name:Toastify__slideOutLeft}.Toastify__slide-exit--bottom-right,.Toastify__slide-exit--top-right{animation-name:Toastify__slideOutRight}.Toastify__slide-exit--top-center{animation-name:Toastify__slideOutUp}.Toastify__slide-exit--bottom-center{animation-name:Toastify__slideOutDown}@keyframes Toastify__spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}'; - - let selfToast; - const useToast = () => { - if (selfToast) return selfToast; - const [root] = useComponentsRoot('toast'); - const _selfToast = (text, options) => { - root.render( - jsxRuntime.jsxs(shadow__default.default.div, { - style: { fontSize: 16 }, - children: [ - jsxRuntime.jsx(reactToastify.ToastContainer, { - autoClose: 1000 * 3, - style: { - // 进度条颜色 - '--toastify-color-progress-light': '#7A909A', - // 背景色 - '--toastify-color-light': 'white', - }, - }), - jsxRuntime.jsxs('style', { - type: 'text/css', - children: [ - ToastStyle.replace(':root', '.Toastify'), - ` - h2 { - font-size: 1.1em; - margin: 0; - margin-bottom: 1em; - } - .md { - text-align: left; - } - .md ul, .md h2 { - margin:0; - margin-bottom: .5em; - font-size: 1em; - } - `, - ], - }), - ], - }), - ); - reactToastify.toast(text, { ...options }); - }; - _selfToast.info = (text, options) => - _selfToast(text, { ...options, type: 'info' }); - _selfToast.error = (text, options) => - _selfToast(text, { ...options, type: 'error' }); - _selfToast.warn = (text, options) => - _selfToast(text, { ...options, type: 'warning' }); - _selfToast.success = (text, options) => - _selfToast(text, { ...options, type: 'success' }); - selfToast = _selfToast; - return selfToast; - }; - - // eslint-disable-next-line import/no-cycle - const sleep = (ms) => - new Promise((resolve) => { - window.setTimeout(resolve, ms); - }); - /** - * 对 document.querySelector 的封装 - * 将默认返回类型改为 HTMLElement - */ - const querySelector = (selector) => document.querySelector(selector); - /** - * 对 document.querySelector 的封装 - * 将默认返回类型改为 HTMLElement - */ - const querySelectorAll = (selector) => [ - ...document.querySelectorAll(selector), - ]; - /** - * 添加元素 - * - * @param node 被添加元素 - * @param textnode 添加元素 - * @param referenceNode 参考元素,添加元素将插在参考元素前 - */ - const insertNode = (node, textnode, referenceNode = null) => { - const temp = document.createElement('div'); - temp.innerHTML = textnode; - const frag = document.createDocumentFragment(); - while (temp.firstChild) frag.appendChild(temp.firstChild); - node.insertBefore(frag, referenceNode); - }; - /** 创建组件用的 ReactDOM Root */ - const useComponentsRoot = (id) => { - // 需要使用动态导入以避免在支持站点外的页面上加载 React - // eslint-disable-next-line @typescript-eslint/consistent-type-imports - const ReactDOM = require('react-dom'); - const dom = - document.getElementById(id) ?? - (() => { - const _dom = document.createElement('div'); - _dom.id = id; - document.body.appendChild(_dom); - return _dom; - })(); - return [ReactDOM.createRoot(dom), dom]; - }; - // 将 xmlHttpRequest 包装为 Promise - const xmlHttpRequest = (details) => - new Promise((resolve, reject) => { - GM_xmlhttpRequest({ - ...details, - onload: resolve, - onerror: reject, - ontimeout: reject, - }); - }); - /** 发起请求 */ - const request = async (url, details, errorNum = 0) => { - const errorText = details?.errorText ?? '漫画加载出错'; - try { - const res = await xmlHttpRequest({ - method: 'GET', - url, - headers: { Referer: window.location.href }, - ...details, - }); - if (res.status !== 200) throw new Error(errorText); - return res; - } catch (error) { - if (errorNum > 3) { - if (errorText) useToast().error(errorText); - throw new Error(errorText); - } - console.error(errorText, error); - await sleep(1000); - return request(url, details, errorNum + 1); - } - }; - - (async () => { - // 某些隐藏漫画虽然被删掉了 PC 端页面,但其实手机版的网页依然还在 - // 所以当跳转至某部漫画的 PC 端页面被提示「页面找不到」时,就先跳转至手机版的页面去 - if (document.title === '页面找不到') { - // 测试例子:https://manhua.dmzj.com/yanquan/48713.shtml - const [, comicName, _chapter_id] = - window.location.pathname.split(/[./]/); - const res = await request(`https://manhua.dmzj.com/${comicName}`); - const _comic_id = /g_comic_id = "(\d+)/.exec(res.responseText)?.[1]; - if (!_comic_id) { - console.error('无法跳转至手机版页面', res); - // eslint-disable-next-line no-alert - alert('无法跳转至手机版页面'); - return; - } - window.location.href = `https://m.dmzj.com/view/${_comic_id}/${_chapter_id}.html`; - return; - } - // 通过 rss 链接,在作者作品页里添加上隐藏漫画的链接 - if (window.location.pathname.includes('/tags/')) { - const res = await request(querySelector('a.rss').href, { - errorText: '获取作者作品失败', - }); - // 页面上原有的漫画标题 - const titleList = querySelectorAll('#hothit p.t').map((e) => - e.innerText.replace('[完]', ''), - ); - insertNode( - document.getElementById('hothit'), - res.responseText - .split('item') - .filter((_, i) => i % 2) - .map((item) => { - const newComicUrl = /manhua.dmzj.com\/(.+?)\?from=rssReader/.exec( - item, - )[1]; - return { - newComicUrl, - comicUrl: newComicUrl.split('/')[0], - title: /title> !titleList.includes(title)) - .map( - (data) => ` - - `, - ) - .join(''), - ); - return; - } - // 跳过漫画目录、漫画页外的其他页面 - if (!Reflect.has(unsafeWindow, 'g_comic_name')) return; - if (!Reflect.has(unsafeWindow, 'g_chapter_name')) { - // 判断当前页是漫画详情页 - // 判断漫画被禁 - // 测试例子:https://manhua.dmzj.com/yanquan/ - if (querySelector('.cartoon_online_border > img')) { - document.querySelector('.cartoon_online_border').innerHTML = - '正在加载中,请坐和放宽,若长时间无反应请刷新页面'; - // XXX: 使用旧 api 只能获取到主版本的章节,其他版本的章节无法取得,改用 v4api 应该就能拿到了 - const res = await request( - `https://api.dmzj.com/dynamic/comicinfo/${g_comic_id}.json`, - { - errorText: '漫画加载出错', - }, - ); - // 删掉原有的章节 dom - querySelectorAll('.odd_anim_title ~ div').forEach((e) => - e.parentNode?.removeChild(e), - ); - const { - info: { last_updatetime, title }, - list: chaptersList, - } = JSON.parse(res.responseText).data; - // 手动构建添加章节 dom - let temp = `

${title}

    `; - let i = chaptersList.length; - while (i--) { - temp += `
  • ${chaptersList[i].chapter_name}
  • `; - } - insertNode( - querySelector('.middleright_mr'), - `${temp}
`, - ); - } - return; - } - // 处理当前页是漫画页的情况 - const { options, setManga, init, onOptionChange } = await helper.useInit( - 'dmzj', - { - 解除吐槽的字数限制: true, - }, - ); - // 切换至上下翻页阅读 - if ($.cookie('display_mode') === '0') unsafeWindow.qiehuan(); - // 根据漫画模式下的夜间模式切换样式 - if (options.option?.darkMode === false) { - document.body.classList.add('day'); - } - onOptionChange((option) => { - // 监听漫画模式下的夜间模式切换,进行实时切换 - if (option.option?.darkMode) document.body.classList.remove('day'); - else document.body.classList.add('day'); - }); - // 添加自定义样式修改 - await GM.addStyle(` - ${JSON.parse(await GM.getResourceText('dmzj_style')).sections[0].code} - - /* 修复和 dmzj_style 的冲突 */ - .mainNav { - display: none !important - } - - /* 增加日间模式的样式 */ - body.day { - background-color: white !important - } - body.day .header-box { - background-color: #DDD !important; - box-shadow: 0 1px 2px white - } - body.day .comic_gd_fb .gd_input { - color: #666; - background: white - } - `); - setManga({ - onNext: helper.querySelectorClick('#next_chapter'), - onPrev: helper.querySelectorClick('#prev_chapter'), - onExit: (isEnd) => { - if (isEnd) { - unsafeWindow.huPoint(); - helper.scrollIntoView('#hd'); - } - setManga({ show: false }); - }, - }); - init(() => - querySelectorAll('.inner_img img') - .map((e) => e.getAttribute('data-original')) - .filter((src) => src), - ); - // 修改发表吐槽的函数,删去字数判断。只是删去了原函数的一个判断条件而已,所以将这段压缩了一下 - if (options.解除吐槽的字数限制) { - const intervalID = setInterval(() => { - if (!unsafeWindow.addpoint) return; - clearInterval(intervalID); - // eslint-disable-next-line - unsafeWindow.addpoint = function () { - const e = $('#gdInput').val(); - const c = $('input[name=length]').val(); - if (e == '') { - alert('沉默是你的个性,但还是吐个槽吧!'); - return false; - } else { - if ($.trim(e) == '') { - alert('空寂是你的个性,但还是吐个槽吧!'); - return false; - } - } - const d = $('#suBtn'); - const b = d.attr('onclick'); - const a = d.html(); - d.attr('onclick', '') - .html('发表中..') - .css({ - background: '#eee', - color: '#999', - cursor: 'not-allowed', - }); - if (is_login) { - $.ajax({ - type: 'get', - url: `${comicUrl}/api/viewpoint/add`, - dataType: 'jsonp', - jsonp: 'callback', - jsonpCallback: 'success_jsonpCallback_201508281119', - data: `type=${type}&type_id=${comic_id}&chapter_id=${chapter_id}&uid=${uid}&nickname=${nickname}&title=${encodeURIComponent( - e, - )}`, - success: function (f) { - if (f.result == 1000) { - $('#gdInput').val(''); - if ($('#moreLi').length > 0) { - $('#moreLi').before( - `
  • ${e}
  • `, - ); - } else { - $('#tc').hide(); - if (c == undefined) { - $('.comic_gd_li').append( - `
  • ${e}
  • `, - ); - } else { - if (c > 9) { - $('.comic_gd_li').append( - `
  • ${e}
  • `, - ); - } else { - $('.comic_gd_li').append( - `
  • ${e}
  • `, - ); - } - } - } - alert('吐槽成功'); - } else { - if (f.result == 2001) { - $('body').append(zcHtml); - zcClick(); - } else { - alert(f.msg); - } - } - d.attr({ onclick: b, style: '' }).html(a); - }, - }); - } - }; - }, 2000); - } - })(); - - break; - } - case 'm.idmzj.com': - case 'm.dmzj.com': { - const helper = require('../helper'); - - // 接口参考 - // https://github.com/xiaoyaocz/flutter_dmzj/blob/ecbe73eb435624022ae5a77156c5d3e0c06809cc/lib/requests/api.dart - // https://github.com/erinacio/tachiyomi-extensions/blob/548be91cccb8f248342e2e7762c2c3d4b2d02036/src/zh/dmzj/src/eu/kanade/tachiyomi/extension/zh/dmzj/Dmzj.kt - (async () => { - const { setManga, init } = await helper.useInit('dmzj', { - 解除吐槽的字数限制: true, - }); - // 分别处理目录页和漫画页 - switch (window.location.pathname.split('/')[1]) { - case 'info': { - // 跳过正常漫画 - if (Reflect.has(unsafeWindow, 'obj_id')) return; - const comicId = parseInt(window.location.pathname.split('/')[2], 10); - if (Number.isNaN(comicId)) { - document.body.removeChild(document.body.childNodes[0]); - helper.insertNode( - document.body, - ` - 请手动输入漫画名进行搜索
    -
    -
    - `, - ); - helper - .querySelector('button') - .addEventListener('click', async () => { - const comicName = helper.querySelector('input')?.value; - if (!comicName) return; - const res = await helper.request( - `https://s.acg.dmzj.com/comicsum/search.php?s=${comicName}`, - { errorText: '搜索漫画时出错' }, - ); - const comicList = JSON.parse(res.responseText.slice(20, -1)); - helper.querySelector('#list').innerHTML = comicList - .map( - ({ id, comic_name, comic_author, comic_url }) => ` - 《${comic_name}》——${comic_author} - Web端 - 移动端 - `, - ) - .join('
    '); - }); - return; - } - // XXX: 使用旧 api 只能获取到主版本的章节,其他版本的章节无法取得,改用 v4api 应该就能拿到了 - const res = await helper.request( - `http://api.dmzj.com/dynamic/comicinfo/${comicId}.json`, - { errorText: '获取漫画数据失败' }, - ); - const { - info: { last_updatetime, title }, - list: chaptersList, - } = JSON.parse(res.responseText).data; - document.title = title; - let temp = `

    ${title}

    `; - let i = chaptersList.length; - while (i--) - temp += `${chaptersList[i].chapter_name}`; - helper.insertNode(document.body, temp); - document.body.removeChild(document.body.childNodes[0]); - await GM.addStyle( - 'body{padding:0 20vw;} a{margin:0 1em;line-height:2em;white-space:nowrap;display:inline-block;min-width:4em;}', - ); - break; - } - case 'view': { - // 如果不是隐藏漫画,直接进入阅读模式 - if (unsafeWindow.comic_id) { - await GM.addStyle('.subHeader{display:none !important}'); - setManga({ - onNext: helper.querySelectorClick('#loadNextChapter'), - onPrev: helper.querySelectorClick('#loadPrevChapter'), - }); - const showComic = init(() => - helper - .querySelectorAll('#commicBox img') - .map((e) => e.getAttribute('data-original')) - .filter((src) => src), - ); - await showComic(); - return; - } - document.body.removeChild(document.body.childNodes[0]); - const tipDom = document.createElement('p'); - tipDom.innerText = '正在加载中,请坐和放宽,若长时间无反应请刷新页面'; - document.body.appendChild(tipDom); - let res; - try { - res = await helper.request( - `https://m.dmzj.com/chapinfo/${ - /\d+\/\d+/.exec(document.URL)[0] - }.html`, - { errorText: '获取漫画数据失败' }, - ); - } catch (error) { - tipDom.innerText = error.message; - throw error; - } - tipDom.innerText = `加载完成,即将进入阅读模式`; - const { folder, page_url } = JSON.parse(res.responseText); - document.title = folder.split('/').at(-2) ?? folder; - // 进入阅读模式后禁止退出,防止返回空白页面 - setManga({ onExit: undefined, editButtonList: (list) => list }); - const showComic = init(() => { - if (page_url.length) return page_url; - tipDom.innerHTML = `无法获得漫画数据,请通过 GithubGreasy Fork 进行反馈`; - return []; - }); - await showComic(); - break; - } - } - })(); - - break; - } - case 'www.idmzj.com': - case 'www.dmzj.com': { - const helper = require('../helper'); - - (async () => { - // 只在漫画页内运行 - if (!Reflect.has(unsafeWindow, 'g_comic_id')) return; - const { setManga, init } = await helper.useInit('dmzj'); - setManga({ - onNext: helper.querySelectorClick('.next > a'), - onPrev: helper.querySelectorClick('.pre > a'), - }); - init(() => picArry.map((url) => `${img_prefix}${url}`)); - })(); - - break; - } - // 懒得整理导入导出的代码了,应该也没人用了吧,等有人需要的时候再说 - // case 'i.dmzj.com': { - // // dmzj_user_info - // break; - // } - - case 'exhentai.org': - case 'e-hentai.org': { - const helper = require('../helper'); - - (async () => { - const { options, setFab, setManga, init, toast } = await helper.useInit( - 'nhentai', - { - 匹配nhentai: true, - 快捷键翻页: true, - }, - ); - // 不是漫画页的话 - if (!Reflect.has(unsafeWindow, 'gid')) { - if (options.快捷键翻页) { - helper.linstenKeyup((e) => { - switch (e.key) { - case 'ArrowRight': - case 'd': - helper.querySelector('#dnext')?.click(); - break; - case 'ArrowLeft': - case 'a': - helper.querySelector('#dprev')?.click(); - break; - } - }); - } - return; - } - setManga({ - onExit: (isEnd) => { - if (isEnd) helper.scrollIntoView('#cdiv'); - setManga({ show: false }); - }, - }); - // 虽然有 Fab 了不需要这个按钮,但都点习惯了没有还挺别扭的( - helper.insertNode( - document.getElementById('gd5'), - '

    Load comic

    ', - ); - const comicReadModeDom = document.getElementById('comicReadMode'); - const totalImgNum = parseInt( - helper.querySelector('#gdd > table > tbody > tr:nth-child(6) > td.gdt2') - .innerHTML, - 10, - ); - let loadedImgNum = 0; - /** - * 从图片页获取图片地址 - */ - const getImgFromImgPage = async (url) => { - const res = await helper.request(url, { - errorText: '从图片页获取图片地址失败', - }); - loadedImgNum += 1; - setFab({ - progress: loadedImgNum / totalImgNum, - tip: `加载图片中 - ${loadedImgNum}/${totalImgNum}`, - }); - comicReadModeDom.innerHTML = ` loading image - ${loadedImgNum}/${totalImgNum}`; - return res.responseText.split('id="img" src="')[1].split('"')[0]; - }; - /** 从详情页获取图片页的地址的正则 */ - const getImgFromDetailsPageRe = - /(?<=\d+ { - const res = await helper.request( - `${window.location.origin}${window.location.pathname}${ - pageNum ? `?p=${pageNum}` : '' - }`, - { - errorText: '从详情页获取图片页地址失败', - }, - ); - // 从详情页获取图片页的地址 - const imgPageList = res.responseText.match(getImgFromDetailsPageRe); - if (imgPageList === null) - throw new Error('从详情页获取图片页的地址时出错'); - return Promise.all(imgPageList.map(getImgFromImgPage)); - }; - const showComic = init( - async () => { - const totalPageNum = +helper.querySelector( - '.ptt td:nth-last-child(2)', - ).innerText; - return ( - await Promise.all( - [...Array(totalPageNum).keys()].map((pageNum) => - getImgFromDetailsPage(pageNum), - ), - ) - ).flat(); - }, - (loadNum, totalNum) => { - comicReadModeDom.innerHTML = - loadNum !== totalNum - ? ` image loading - ${loadNum}/${totalNum}` - : ' Read'; - }, - ); - setFab({ initShow: options.autoShow }); - comicReadModeDom.addEventListener('click', showComic); - if (options.快捷键翻页) { - helper.linstenKeyup((e) => { - switch (e.key) { - case 'ArrowRight': - case 'd': - helper.querySelector('.ptt td:last-child:not(.ptdd)')?.click(); - break; - case 'ArrowLeft': - case 'a': - helper.querySelector('.ptt td:first-child:not(.ptdd)')?.click(); - break; - } - }); - } - if (options.匹配nhentai) { - const titleDom = document.getElementById('gn'); - const taglistDom = helper.querySelector('#taglist tbody'); - if (!titleDom || !taglistDom) { - toast.error('页面结构发生改变,匹配 nhentai 漫画功能无法正常生效'); - return; - } - const newTagLine = document.createElement('tr'); - let res; - try { - res = await helper.request( - `https://nhentai.net/api/galleries/search?query=${encodeURI( - titleDom.innerText, - )}`, - { errorText: '' }, - ); - } catch (_) { - newTagLine.innerHTML = ` - nhentai: - - 匹配失败,请确认 nhentai 登录状态 - `; - taglistDom.appendChild(newTagLine); - return; - } - const nHentaiComicInfo = JSON.parse(res.responseText); - // 构建新标签行 - if (nHentaiComicInfo.result.length) { - let temp = 'nhentai:'; - let i = nHentaiComicInfo.result.length; - while (i) { - i -= 1; - const tempComicInfo = nHentaiComicInfo.result[i]; - temp += ``; - } - newTagLine.innerHTML = `${temp}`; - } else - newTagLine.innerHTML = - 'nhentai:Null'; - taglistDom.appendChild(newTagLine); - // 重写 _refresh_tagmenu_act 函数,加入脚本的功能 - const nhentaiImgList = {}; - unsafeWindow._refresh_tagmenu_act = function _refresh_tagmenu_act( - a, - b, - ) { - const tagmenu_act_dom = document.getElementById('tagmenu_act'); - if (a.includes('nhentai:')) { - tagmenu_act_dom.innerHTML = `> Jump to nhentai`; - tagmenu_act_dom.innerHTML += `> ${ - nhentaiImgList[selected_tag] ? 'Read' : 'Load comic' - }`; - const nhentaiComicReadModeDom = - tagmenu_act_dom.querySelector('a[href="#"]'); - // 加载 nhentai 漫画 - nhentaiComicReadModeDom.addEventListener('click', async (e) => { - e.preventDefault(); - const comicInfo = - nHentaiComicInfo.result[+selected_link.getAttribute('index')]; - let loadNum = 0; - if (!nhentaiImgList[selected_tag]) { - nhentaiComicReadModeDom.innerHTML = ` loading - ${loadNum}/${comicInfo.num_pages}`; - // 用于转换获得图片文件扩展名的 dict - const fileType = { - j: 'jpg', - p: 'png', - g: 'gif', - }; - nhentaiImgList[selected_tag] = await Promise.all( - comicInfo.images.pages.map(async ({ t }, i) => { - const imgRes = await helper.request( - `https://i.nhentai.net/galleries/${comicInfo.media_id}/${ - i + 1 - }.${fileType[t]}`, - { - headers: { - Referer: `https://nhentai.net/g/${comicInfo.media_id}`, - }, - responseType: 'blob', - }, - ); - const blobUrl = URL.createObjectURL(imgRes.response); - loadNum += 1; - nhentaiComicReadModeDom.innerHTML = ` loading - ${loadNum}/${comicInfo.num_pages}`; - return blobUrl; - }), - ); - nhentaiComicReadModeDom.innerHTML = ' Read'; - } - setManga({ imgList: nhentaiImgList[selected_tag], show: true }); - }); - } else { - const mr = - '>'; - let temp = ''; - if (b.className !== 'tup') - temp += ` ${mr} ${ - b.className === '' ? 'Vote Up' : 'Withdraw Vote' - }`; - if (b.className !== 'tdn') - temp += ` ${mr} ${ - b.className === '' ? 'Vote Down' : 'Withdraw Vote' - }`; - // 删掉原有的 Show Tagged Galleries 按钮空出位置 - temp += `${mr} Show Tag Definition${mr} Add New Tag ${mr} `; - const tag = selected_link.id.slice(3).split(':'); - if (tag.length === 1) { - temp += `Jump to nhentai`; - } else { - temp += `Jump to nhentai`; - } - tagmenu_act_dom.innerHTML = temp; - } - }; - } - })(); - - break; - } - - case 'nhentai.net': { - const helper = require('../helper'); - - /** 用于转换获得图片文件扩展名 */ - const fileType = { - j: 'jpg', - p: 'png', - g: 'gif', - }; - (async () => { - const { options, setFab, setManga, toast, init } = await helper.useInit( - 'nhentai', - { - 自动翻页: true, - 彻底屏蔽漫画: true, - 在新页面中打开链接: true, - }, - ); - // 在漫画详情页 - if (Reflect.has(unsafeWindow, 'gallery')) { - setManga({ - onExit: (isEnd) => { - if (isEnd) helper.scrollIntoView('#comment-container'); - setManga({ show: false }); - }, - }); - // 虽然有 Fab 了不需要这个按钮,但我自己都点习惯了没有还挺别扭的( - helper.insertNode( - document.getElementById('download').parentNode, - ' Load comic', - ); - const comicReadModeDom = document.getElementById('comicReadMode'); - const showComic = init( - () => - gallery.images.pages.map( - ({ number, extension }) => - `https://i.nhentai.net/galleries/${gallery.media_id}/${number}.${extension}`, - ), - (loadNum, totalNum) => { - comicReadModeDom.innerHTML = - loadNum !== totalNum - ? ` loading —— ${loadNum}/${totalNum}` - : ' Read'; - }, - ); - setFab({ initShow: options.autoShow }); - comicReadModeDom.addEventListener('click', showComic); - return; - } - // 在漫画浏览页 - if (document.getElementsByClassName('gallery').length) { - if (options.在新页面中打开链接) - helper - .querySelectorAll('a:not([href^="javascript:"])') - .forEach((e) => e.setAttribute('target', '_blank')); - const blacklist = (unsafeWindow?._n_app ?? unsafeWindow?.n)?.options - ?.blacklisted_tags; - if (blacklist === undefined) toast.error('标签黑名单获取失败'); - // blacklist === null 时是未登录 - if (options.彻底屏蔽漫画 && blacklist?.length) - await GM.addStyle('.blacklisted.gallery { display: none; }'); - if (options.自动翻页) { - await GM.addStyle(` - hr { bottom: 0; box-sizing: border-box; margin: -1em auto 2em; } - hr:last-child { position: relative; animation: load .8s linear alternate infinite; } - hr:not(:last-child) { display: none; } - @keyframes load { 0% { width: 100%; } 100% { width: 0; } } - `); - let pageNum = Number( - helper.querySelector('.page.current')?.innerHTML ?? '', - ); - if (Number.isNaN(pageNum)) return; - let loadLock = !pageNum; - const contentDom = document.getElementById('content'); - const apiUrl = (() => { - if (window.location.pathname === '/') - return 'https://nhentai.net/api/galleries/all?'; - if (helper.querySelector('a.tag')) - return `https://nhentai.net/api/galleries/tagged?tag_id=${ - helper.querySelector('a.tag')?.classList[1].split('-')[1] - }&`; - if (window.location.pathname.includes('search')) - return `https://nhentai.net/api/galleries/search?query=${new URLSearchParams( - window.location.search, - ).get('q')}&`; - return ''; - })(); - const loadNewComic = async () => { - if ( - loadLock || - contentDom.lastElementChild.getBoundingClientRect().top > - window.innerHeight - ) - return undefined; - loadLock = true; - pageNum += 1; - const res = await helper.request( - `${apiUrl}page=${pageNum}${ - window.location.pathname.includes('popular') - ? '&sort=popular ' - : '' - }`, - { errorText: '下一页漫画信息加载出错' }, - ); - const { result, num_pages } = JSON.parse(res.responseText); - let comicDomHtml = ''; - // 在 用户已登录 且 有设置标签黑名单 且 开启了彻底屏蔽功能时,才对结果进行筛选 - (options.彻底屏蔽漫画 && blacklist?.length - ? result.filter(({ tags }) => - tags.every((tag) => !blacklist.includes(tag.id)), - ) - : result - ).forEach((comic) => { - comicDomHtml += ``; - }); - // 构建页数按钮 - if (comicDomHtml) { - const target = options.在新页面中打开链接 - ? 'target="_blank" ' - : ''; - const pageNumDom = []; - for (let i = pageNum - 5; i <= pageNum + 5; i += 1) { - if (i > 0 && i <= num_pages) - pageNumDom.push( - `${i}`, - ); - } - helper.insertNode( - contentDom, - `

    ${pageNum}

    -
    ${comicDomHtml}
    -
    - - - - - - ${pageNumDom.join('')} - ${ - pageNum === num_pages - ? '' - : ` - - - - ` - } -
    `, - ); - } - // 添加分隔线 - contentDom.appendChild(document.createElement('hr')); - if (pageNum < num_pages) loadLock = false; - else - contentDom.lastElementChild.style.animationPlayState = 'paused'; - // 当前页的漫画全部被屏蔽或当前显示的漫画少到连滚动条都出不来时,继续加载 - if ( - !comicDomHtml || - contentDom.offsetHeight < document.body.offsetHeight - ) - return loadNewComic(); - return undefined; - }; - window.addEventListener('scroll', loadNewComic); - if (helper.querySelector('section.pagination')) - contentDom.appendChild(document.createElement('hr')); - await loadNewComic(); - } - } - })(); - - break; - } - - case 'copymanga.site': - case 'copymanga.info': - case 'copymanga.net': - case 'copymanga.org': - case 'copymanga.com': - case 'www.copymanga.site': - case 'www.copymanga.info': - case 'www.copymanga.net': - case 'www.copymanga.org': - case 'www.copymanga.com': { - const helper = require('../helper'); - - (async () => { - // 只在漫画页内运行 - if (!window.location.href.includes('/chapter/')) return; - const { setManga, init } = await helper.useInit('copymanga'); - setManga({ - onNext: helper.querySelectorClick( - '.comicContent-next a:not(.prev-null)', - ), - onPrev: helper.querySelectorClick( - '.comicContent-prev:not(.index,.list) a:not(.prev-null)', - ), - }); - init(async () => { - const res = await helper.request( - window.location.href.replace( - /.*?(?=\/comic\/)/, - 'https://api.copymanga.site/api/v3', - ), - ); - const { - results: { - chapter: { contents }, - }, - } = JSON.parse(res.responseText); - return contents.map(({ url }) => url); - }); - })(); - - break; - } - - case 'tel.dm5.com': - case 'en.dm5.com': - case 'www.dm5.com': - case 'www.dm5.cn': - case 'www.1kkk.com': { - const helper = require('../helper'); - - (async () => { - // 只在漫画页内运行 - if (!Reflect.has(unsafeWindow, 'DM5_CID')) return; - const { setFab, toast, setManga, init } = await helper.useInit('dm5'); - setManga({ - onNext: helper.querySelectorClick('.logo_2'), - onPrev: helper.querySelectorClick('.logo_1'), - onExit: (isEnd) => { - if (isEnd) helper.scrollIntoView('.top'); - setManga({ show: false }); - }, - }); - const getImgList = async (imgList = [], errorNum = 0) => { - try { - const res = await $.ajax({ - type: 'GET', - url: 'chapterfun.ashx', - data: { - cid: DM5_CID, - page: imgList.length + 1, - key: $('#dm5_key').length ? $('#dm5_key').val() : '', - language: 1, - gtk: 6, - _cid: DM5_CID, - _mid: DM5_MID, - _dt: DM5_VIEWSIGN_DT, - _sign: DM5_VIEWSIGN, - }, - }); - // 返回的数据只能通过 eval 获得 - // eslint-disable-next-line no-eval - const newImgList = [...imgList, ...eval(res)]; - if (newImgList.length !== DM5_IMAGE_COUNT) { - setFab({ - progress: newImgList.length / DM5_IMAGE_COUNT, - tip: `加载图片中 - ${newImgList.length}/${DM5_IMAGE_COUNT}`, - }); - return getImgList(newImgList); - } - return newImgList; - } catch (error) { - if (errorNum > 3) throw new Error('加载图片时出错'); - console.error('加载图片时出错'); - toast.error('加载图片时出错'); - await helper.sleep(1000 * 3); - return getImgList(imgList, errorNum + 1); - } - }; - init(getImgList); - })(); - - break; - } - - case 'www.mangabz.com': - case 'mangabz.com': { - const helper = require('../helper'); - - (async () => { - // 只在漫画页内运行 - if (!Reflect.has(unsafeWindow, 'MANGABZ_CID')) return; - const { setFab, setManga, init } = await helper.useInit('mangabz'); - setManga({ - onNext: helper.querySelectorClick( - 'body > .container a[href^="/"]:last-child', - ), - onPrev: helper.querySelectorClick( - 'body > .container a[href^="/"]:first-child', - ), - }); - const getImgList = async (imgList = []) => { - const urlParams = helper.dataToParams({ - cid: MANGABZ_CID, - page: imgList.length + 1, - key: '', - _cid: MANGABZ_CID, - _mid: MANGABZ_MID, - _dt: MANGABZ_VIEWSIGN_DT.replace(' ', '+').replace(':', '%3A'), - _sign: MANGABZ_VIEWSIGN, - }); - const res = await helper.request( - `http://${MANGABZ_COOKIEDOMAIN}${MANGABZ_CURL}chapterimage.ashx?${urlParams}`, - ); - // 返回的数据只能通过 eval 获得 - // eslint-disable-next-line no-eval - const newImgList = [...imgList, ...eval(res.responseText)]; - if (newImgList.length !== MANGABZ_IMAGE_COUNT) { - // 在 Fab 按钮上通过进度条和提示文本显示当前进度 - setFab({ - progress: newImgList.length / MANGABZ_IMAGE_COUNT, - tip: `加载图片中 - ${newImgList.length}/${MANGABZ_IMAGE_COUNT}`, - }); - return getImgList(newImgList); - } - return newImgList; - }; - init(getImgList); - })(); - - break; - } - - case 'www.manhuagui.com': - case 'www.mhgui.com': - case 'tw.manhuagui.com': { - const helper = require('../helper'); - - (async () => { - // 只在漫画页内运行 - if (!Reflect.has(unsafeWindow, 'cInfo')) return; - const { setManga, init } = await helper.useInit('manhuagui'); - setManga({ - onNext: - cInfo.nextId !== 0 ? helper.querySelectorClick('a.nextC') : null, - onPrev: - cInfo.prevId !== 0 ? helper.querySelectorClick('a.prevC') : null, - }); - init(() => { - const comicInfo = JSON.parse( - // 只能通过 eval 获得数据 - // eslint-disable-next-line no-eval - eval( - document.querySelectorAll('body > script')[1].innerHTML.slice(26), - ).slice(12, -12), - ); - const sl = Object.entries(comicInfo.sl) - .map((attr) => `${attr[0]}=${attr[1]}`) - .join('&'); - return comicInfo.files.map( - (file) => `${pVars.manga.filePath}${file}?${sl}`, - ); - }); - })(); - - break; - } - - case 'www.manhuadb.com': { - const helper = require('../helper'); - - (async () => { - // 只在漫画页内运行 - if (!Reflect.has(unsafeWindow, 'img_data_arr')) return; - const { setManga, init } = await helper.useInit('manhuaDB'); - /** - * 检查是否有上/下一话 - */ - const checkTurnPage = async (type) => { - const res = await $.ajax({ - method: 'POST', - url: '/book/goNumPage', - dataType: 'json', - data: helper.dataToParams({ - ccid: p_ccid, - id: p_id, - num: vg_r_data.data('num') + (type === 'next' ? 1 : -1), - d: p_d, - type, - }), - }); - if (res.state) - return helper.querySelectorClick( - `a[title="${type === 'next' ? '下集' : '上集'}"]`, - ); - return null; - }; - setManga({ - onNext: await checkTurnPage('next'), - onPrev: await checkTurnPage('pre'), - }); - init(() => - img_data_arr.map((data) => `${img_host}/${img_pre}/${data.img}`), - ); - })(); - - break; - } - - case 'www.manhuacat.com': - case 'www.maofly.com': { - const helper = require('../helper'); - - (async () => { - // 只在漫画页内运行 - if (!Reflect.has(unsafeWindow, 'cdnImage')) return; - const { setManga, init } = await helper.useInit('manhuacat'); - /** - * 检查是否有上/下一页 - */ - const checkTurnPage = async (type) => { - const res = await $.ajax({ - type: 'get', - url: `/chapter_num?chapter_id=${chapter_num}&ctype=${ - type === 'next' ? 1 : 2 - }&type=${chapter_type}`, - dataType: 'json', - }); - if (res.code === '0000') return () => goNumPage(type); - return null; - }; - setManga({ - onNext: await checkTurnPage('next'), - onPrev: await checkTurnPage('pre'), - }); - init(() => - img_data_arr.map((img) => - cdnImage(img_pre + img, asset_domain, asset_key), - ), - ); - })(); - - break; - } - - case 'jmcomic.me': - case 'jmcomic1.me': - case '18comic.org': - case '18comic.cc': - case '18comic.vip': { - const helper = require('../helper'); - - (async () => { - // 只在漫画页内运行 - if (!window.location.pathname.includes('/photo/')) return; - const { init, setFab, toast } = await helper.useInit('jm'); - while (!unsafeWindow?.onImageLoaded) { - if (document.readyState === 'complete') { - toast.error('无法获取图片', { autoClose: false }); - return; - } - // eslint-disable-next-line no-await-in-loop - await helper.sleep(100); - } - const imgEleList = helper.querySelectorAll('.scramble-page > img'); - // 判断当前漫画是否有被分割,没有就直接获取图片链接加载 - // 判断条件来自页面上的 scramble_image 函数 - if ( - unsafeWindow.aid < unsafeWindow.scramble_id || - unsafeWindow.speed === '1' - ) { - init(() => imgEleList.map((e) => e.getAttribute('data-original'))); - return; - } - const getImgUrl = async (imgEle) => { - const res = await helper.request(imgEle.getAttribute('data-original'), { - responseType: 'blob', - }); - imgEle.src = URL.createObjectURL(res.response); - await new Promise((resolve, reject) => { - imgEle.onload = resolve; - imgEle.onerror = reject; - }); - unsafeWindow.onImageLoaded(imgEle); - const blob = await new Promise((resolve) => { - imgEle.nextElementSibling.toBlob(resolve, 'image/webp', 1); - }); - if (!blob) return ''; - return `${URL.createObjectURL(blob)}#.webp`; - }; - init(() => - helper.plimit( - 10, - imgEleList.map((img) => async () => getImgUrl(img)), - (resList) => { - setFab({ - progress: resList.length / imgEleList.length, - tip: `加载图片中 - ${resList.length}/${imgEleList.length}`, - }); - }, - ), - ); - })(); - - break; - } - - default: { - const helper = require('../helper'); - - /** - * 对修改站点配置的相关方法的封装 - * - * @param name 站点名 - * @param defaultOptions 默认配置 - */ - const useSiteOptions = async (name, defaultOptions = {}) => { - const rawValue = await GM.getValue(name); - const options = Object.assign( - { - option: undefined, - autoShow: true, - hiddenFAB: false, - ...defaultOptions, - }, - rawValue, - ); - const changeCallbackList = []; - return { - options, - /** 该站点是否有储存配置 */ - isRecorded: rawValue !== undefined, - /** - * 设置新 Option - * - * @param newValue newValue - * @param trigger 是否触发变更事件 - */ - setOptions: async (newValue, trigger = true) => { - Object.assign(options, newValue); - await GM.setValue(name, options); - if (trigger) - await Promise.all( - changeCallbackList.map((callback) => callback(options)), - ); - }, - /** - * 监听配置变更事件 - */ - onOptionChange: (callback) => { - changeCallbackList.push(callback); - }, - }; - }; - - setTimeout(async () => { - const { options, setOptions, isRecorded, onOptionChange } = - await useSiteOptions(window.location.hostname, { autoShow: false }); - /** 图片列表 */ - let imgList = []; - /** 是否正在后台不断检查图片 */ - let running = 0; - let setManga; - let setFab; - let toast; - const init = async () => { - if (setManga !== undefined) return; - [setManga] = await helper.useManga({ - imgList, - show: options.autoShow, - onOptionChange: (option) => setOptions({ ...options, option }, false), - }); - setManga(helper.setToolbarButton, false); - setFab = await helper.useFab({ - tip: '阅读模式', - onClick: () => setManga({ show: true }), - speedDial: helper.defaultSpeedDial(options, setOptions), - }); - onOptionChange(() => setFab()); - setFab(); - toast = helper.useToast(); - }; - /** 已经被触发过懒加载的图片 */ - const triggedImgList = new Set(); - /** 触发懒加载 */ - const triggerLazyLoad = () => { - const targetImgList = [...document.getElementsByTagName('img')] - // 过滤掉已经被触发过懒加载的图片 - .filter((e) => !triggedImgList.has(e)) - // 根据位置从小到大排序 - .sort((a, b) => a.offsetTop - b.offsetTop); - /** 上次触发的图片 */ - let lastTriggedImg; - targetImgList.forEach((e) => { - triggedImgList.add(e); - // 过滤掉位置相近,在触发上一张图片时已经顺带被触发了的 - if ( - e.offsetTop >= - (lastTriggedImg?.offsetTop ?? 0) + window.innerHeight - ) - return; - // 通过瞬间滚动到图片位置、触发滚动事件、再瞬间滚回来,来触发图片的懒加载 - const nowScroll = window.scrollY; - window.scroll({ top: e.offsetTop, behavior: 'auto' }); - e.dispatchEvent(new Event('scroll', { bubbles: true })); - window.scroll({ top: nowScroll, behavior: 'auto' }); - lastTriggedImg = e; - }); - }; - /** - * 检查搜索页面上符合标准的图片 - * - * @returns 返回是否成功找到图片 - */ - const checkFindImg = () => { - triggerLazyLoad(); - const newImgList = [...document.getElementsByTagName('img')] - .filter((e) => e.naturalHeight > 500 && e.naturalWidth > 500) - .map((e) => e.src); - if (newImgList.length === 0) { - if (!options.autoShow) { - clearInterval(running); - toast?.('没有找到图片', { type: 'warning' }); - } - return false; - } - // 在发现新图片后重新渲染 - if (!helper.isEqualArray(imgList, newImgList)) { - imgList = newImgList; - setManga({ imgList }); - setFab({ progress: 1 }); - } - return true; - }; - await GM.registerMenuCommand('进入漫画阅读模式', async () => { - await init(); - if (!running) running = window.setInterval(checkFindImg, 2000); - if (!checkFindImg()) return; - setManga({ show: true }); - // 自动启用自动加载功能 - await setOptions({ ...options, autoShow: true }); - }); - if (isRecorded) { - await init(); - // 为了保证兼容,只能简单粗暴的不断检查网页的图片来更新数据 - running = window.setInterval(checkFindImg, 2000); - await GM.registerMenuCommand('停止在此站点自动运行脚本', async () => { - await GM.deleteValue(window.location.hostname); - }); - } - }); - } -} diff --git a/ComicReadScript.code-workspace b/ComicReadScript.code-workspace deleted file mode 100644 index 1abe0ccd..00000000 --- a/ComicReadScript.code-workspace +++ /dev/null @@ -1,26 +0,0 @@ -{ - "folders": [ - { - "path": ".", - "name": "root" - }, - { - "path": "packages/userscript", - "name": "userscript" - }, - { - "path": "packages/ui-component", - "name": "ui-component" - } - ], - "settings": { - "typescript.tsdk": "root\\node_modules\\typescript\\lib", - "explorer.autoRevealExclude": { - "README*.md": true - }, - "workbench.colorCustomizations": { - "minimap.background": "#23272e88", - "scrollbar.shadow": "#23272e88" - } - }, -} diff --git a/docs/Dev.md b/docs/Dev.md index 5fd7b520..d4412a9e 100644 --- a/docs/Dev.md +++ b/docs/Dev.md @@ -1,11 +1,14 @@ ## TODO -- 百合会更新后自动签到失效了 - 长图自动开启卷轴模式 https://bbs.yamibo.com/thread-534775-1-1.html -- 页数加一 - 测试平板上的使用 - 卷轴模式下滚动到底要能触发结束页 - 放大后侧边栏按钮悬浮背景色变为半透明会导致看不清图标 +- 检查控制台警告 +- 300 自动签到功能在菜单切换时没有实时刷新 +- 为图片增加背景,以便用户知道当前图片正在加载 +- 百合会退出时有点卡 +- 填充页位置调整 https://bbs.yamibo.com/thread-535108-1-1.html ## 项目结构 @@ -20,7 +23,6 @@ ## 调试 ```bash -cd packages/userscript pnpm dev ``` @@ -52,6 +54,8 @@ Object.fromEntries( 3. 如果有上下一话的按钮,就通过 `setManga` 修改 onNext、onPrev 两个参数。注意如果按钮存在但无法点击的话,应该传递空值或直接不传 4. 向 `init` 函数传一个返回所有图片链接的函数 +--- + ## 动态导入外部库 `src\helper\import.ts` @@ -59,3 +63,11 @@ Object.fromEntries( 不过因为有些 cjs 会使用 node 环境特有的变量、在模块里再 require() 其他模块(这种情况下也需要将其依赖模块在 @resource 中声明),所以尽量还是选择 umd 的代码。 另外为了尽量减少在无关页面浪费时间,components、helper 下的代码会被打包视为外部库 `'../helper'` 来使用,如果只需要其中一段代码则通过 `helper/XXX` 来导入即可。 + +## pnpm dev + +这个命令总共会做三件事 + +1. 打包代码到 dist +2. 创建 dist 的文件服务器,用于在浏览器获取最新的脚本代码 +3. 使用 vite 加载 src\components\display.tsx 以便单独测试组件 diff --git a/packages/ui-component/index.html b/index.html similarity index 89% rename from packages/ui-component/index.html rename to index.html index ede0536d..ed162e93 100644 --- a/packages/ui-component/index.html +++ b/index.html @@ -10,7 +10,7 @@
    - + - - - )); - - const set = (recipe: ((draftProps: FabProps) => void) | Partial) => - setProps(typeof recipe === 'function' ? produce(recipe) : recipe); - - return set; -}; diff --git a/packages/ui-component/src/useComponents/Manga.tsx b/packages/ui-component/src/useComponents/Manga.tsx deleted file mode 100644 index 06a03076..00000000 --- a/packages/ui-component/src/useComponents/Manga.tsx +++ /dev/null @@ -1,77 +0,0 @@ -/* eslint-disable import/no-relative-packages */ - -import { createStore, produce } from 'solid-js/store'; -import { IconButtonStyle } from '../components/IconButton'; -import type { MangaProps } from '../components/Manga'; -import { MangaStyle, Manga } from '../components/Manga'; -import { mountComponents } from '../helper'; - -export type SelfMangaProps = MangaProps & { - show: boolean; - handleExit: MangaProps['onExit']; -}; - -/** - * 显示漫画阅读窗口 - */ -export const useManga = async (initProps?: Partial) => { - await GM.addStyle(` - #comicRead { - position: fixed; - z-index: 999999999; - top: 0; - left: 0; - - width: 100vw; - height: 100vh; - - font-size: 16px; - - opacity: 1; - - transition: opacity 300ms, transform 100ms; - } - - #comicRead.hidden { - transform: scale(0); - - opacity: 0; - - transition: opacity 300ms, transform 0s 300ms; - } - `); - - const [props, setProps] = createStore({ - imgList: [], - show: false, - ...initProps, - } as SelfMangaProps); - - const dom = mountComponents('comicRead', () => ( - <> - - - - - )); - - const set = ( - recipe: ((draftProps: SelfMangaProps) => void) | Partial, - ) => { - setProps(typeof recipe === 'function' ? produce(recipe) : recipe); - - if (props.imgList.length && props.show) { - dom.className = ''; - document.documentElement.style.overflow = 'hidden'; - } else { - dom.className = 'hidden'; - document.documentElement.style.overflow = 'unset'; - } - }; - - setProps({ - onExit: () => set({ show: false }), - }); - - return [set, props] as [typeof set, SelfMangaProps]; -}; diff --git a/packages/ui-component/src/useComponents/Toast.tsx b/packages/ui-component/src/useComponents/Toast.tsx deleted file mode 100644 index 2120b50c..00000000 --- a/packages/ui-component/src/useComponents/Toast.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import toast, { Toaster } from 'solid-toast'; -import { useComponentsRoot } from '../helper'; - -let mounted = false; - -export const useToast = () => { - if (!mounted) { - const [render] = useComponentsRoot('toast'); - render(() => ); - mounted = true; - } - - return toast; -}; diff --git a/packages/ui-component/tsconfig.json b/packages/ui-component/tsconfig.json deleted file mode 100644 index dec2e49a..00000000 --- a/packages/ui-component/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "types": ["vite/client"] - }, - "include": [ - "src", - "*.ts" - ] -} diff --git a/packages/ui-component/vite.config.ts b/packages/ui-component/vite.config.ts deleted file mode 100644 index dd2c618c..00000000 --- a/packages/ui-component/vite.config.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { defineConfig } from 'vite'; -import solid from 'vite-plugin-solid'; -import SolidSvg from 'vite-plugin-solid-svg'; - -/** 开发服务器的端口 */ -export const DEV_PORT = 2405; - -export default defineConfig({ - server: { - host: true, - port: DEV_PORT, - cors: false, - }, - plugins: [ - SolidSvg({ - svgo: { - enabled: true, - svgoConfig: { - plugins: [ - 'preset-default', - { - name: 'addAttributesToSVGElement', - params: { - attribute: { - stroke: 'currentColor', - fill: 'currentColor', - 'stroke-width': '0', - }, - }, - }, - ], - }, - }, - }), - solid(), - ], -}); diff --git a/packages/userscript/.vscode/launch.json b/packages/userscript/.vscode/launch.json deleted file mode 100644 index b0f714cd..00000000 --- a/packages/userscript/.vscode/launch.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - // 使用 IntelliSense 了解相关属性。 - // 悬停以查看现有属性的描述。 - // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "command": "pnpm run build", - "name": "debug npm", - "request": "launch", - "type": "node-terminal" - } - ] -} diff --git a/packages/userscript/package.json b/packages/userscript/package.json deleted file mode 100644 index 2bde7230..00000000 --- a/packages/userscript/package.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "name": "@crs/userscript", - "version": "0.0.1", - "private": "true", - "description": "", - "scripts": { - "dev": "rollup --config --watch --environment NODE_ENV:development --configPlugin 'rollup-plugin-esbuild={target: \"esnext\"}'", - "build": "rollup --config --configPlugin 'rollup-plugin-esbuild={target: \"esnext\"}'", - "test": "vitest" - }, - "author": "hymbz", - "license": "AGPL-3.0-or-later", - "dependencies": { - "@crs/ui-component": "workspace:*", - "@material-design-icons/svg": "^0.14.6", - "core-js": "^3.30.1", - "fflate": "^0.7.4", - "solid-js": "^1.7.3", - "solid-toast": "^0.5.0" - }, - "devDependencies": { - "@babel/core": "^7.21.4", - "@babel/plugin-transform-runtime": "^7.21.4", - "@babel/preset-env": "^7.21.4", - "@babel/preset-typescript": "^7.21.4", - "@babel/runtime": "^7.21.0", - "@rollup/plugin-babel": "^6.0.3", - "@rollup/plugin-commonjs": "^24.1.0", - "@rollup/plugin-json": "^6.0.0", - "@rollup/plugin-node-resolve": "^15.0.2", - "@rollup/plugin-replace": "^5.0.2", - "@types/node": "^18.15.11", - "babel-plugin-inline-react-svg": "^2.0.2", - "babel-preset-solid": "^1.7.3", - "esbuild": "^0.17.17", - "esbuild-plugin-solid": "^0.5.0", - "rollup": "^3.20.6", - "rollup-plugin-delete": "^2.0.0", - "rollup-plugin-esbuild": "^5.0.0", - "rollup-plugin-import-css": "^3.2.1", - "rollup-plugin-prettier": "^3.0.0", - "rollup-plugin-serve": "^2.0.2", - "rollup-plugin-ts": "^3.2.0", - "rollup-plugin-userscript-metablock": "^0.3.2", - "rollup-plugin-watch-assets": "^1.0.1", - "svgo": "^3.0.2", - "utility-types": "^3.10.0" - } -} diff --git a/packages/userscript/resource.json b/packages/userscript/resource.json deleted file mode 100644 index 3b6658b9..00000000 --- a/packages/userscript/resource.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "dev": { - "solid-js": "https://unpkg.com/solid-js@1.7.3/dist/dev.cjs", - "solid-js/store": "https://unpkg.com/solid-js@1.7.3/store/dist/dev.cjs", - "solid-js/web": "https://unpkg.com/solid-js@1.7.3/web/dist/dev.cjs", - "panzoom": "https://unpkg.com/panzoom@9.4.3/dist/panzoom.min.js", - "fflate": "https://unpkg.com/fflate@0.7.4/umd/index.js", - "dmzj_style": "https://userstyles.org/styles/chrome/119945.json" - }, - "prod": { - "solid-js": "https://unpkg.com/solid-js@1.7.3/dist/solid.cjs", - "solid-js/store": "https://unpkg.com/solid-js@1.7.3/store/dist/store.cjs", - "solid-js/web": "https://unpkg.com/solid-js@1.7.3/web/dist/web.cjs", - "panzoom": "https://unpkg.com/panzoom@9.4.3/dist/panzoom.min.js", - "fflate": "https://unpkg.com/fflate@0.7.4/umd/index.js", - "dmzj_style": "https://userstyles.org/styles/chrome/119945.json" - } -} diff --git a/packages/userscript/rollup.config.ts b/packages/userscript/rollup.config.ts deleted file mode 100644 index 951bd008..00000000 --- a/packages/userscript/rollup.config.ts +++ /dev/null @@ -1,274 +0,0 @@ -/* eslint-disable no-restricted-syntax */ -/* eslint-disable import/no-extraneous-dependencies */ -import fs from 'fs'; -import type { OutputPlugin, RollupOptions, Plugin } from 'rollup'; -import { nodeResolve } from '@rollup/plugin-node-resolve'; -import commonjs from '@rollup/plugin-commonjs'; -import replace from '@rollup/plugin-replace'; -import ts from 'rollup-plugin-ts'; -import esbuild from 'rollup-plugin-esbuild'; -import prettier from 'rollup-plugin-prettier'; -import css from 'rollup-plugin-import-css'; -import del from 'rollup-plugin-delete'; -import serve from 'rollup-plugin-serve'; -import watchAssets from 'rollup-plugin-watch-assets'; -import { babel } from '@rollup/plugin-babel'; - -import type { MetaValues } from 'rollup-plugin-userscript-metablock'; -import metablock from 'rollup-plugin-userscript-metablock'; - -// eslint-disable-next-line import/no-relative-packages -import pkg from '../../package.json' assert { type: 'json' }; -import resource from './resource.json' assert { type: 'json' }; - -const isDevMode = process.env.NODE_ENV === 'development'; - -export const meta = { - name: pkg.name, - namespace: pkg.name, - version: pkg.version, - description: pkg.description, - author: pkg.author, - license: pkg.license, - - noframes: true, - match: '*://*/*', - connect: [ - 'cdn.jsdelivr.net', - 'yamibo.com', - 'dmzj.com', - 'idmzj.com', - 'exhentai.org', - 'e-hentai.org', - 'nhentai.net', - 'mangabz.com', - 'copymanga.site', - 'copymanga.info', - 'copymanga.net', - 'copymanga.org', - 'copymanga.com', - '*', - ], - grant: [ - 'GM_addElement', - 'GM_getResourceText', - 'GM_xmlhttpRequest', - 'GM.getResourceText', - 'GM.addStyle', - 'GM.getValue', - 'GM.setValue', - 'GM.deleteValue', - 'GM.registerMenuCommand', - 'GM.unregisterMenuCommand', - 'unsafeWindow', - ], - resource: resource[isDevMode ? 'dev' : 'prod'], - supportURL: 'https://github.com/hymbz/ComicReadScript/issues', - updateURL: - 'https://github.com/hymbz/ComicReadScript/raw/master/ComicRead.user.js', - downloadURL: - 'https://github.com/hymbz/ComicReadScript/raw/master/ComicRead.user.js', -} as MetaValues; - -/** 开发服务器的端口 */ -const DEV_PORT = '2405'; -const siteFileList = fs.readdirSync('src/site'); - -const buildConfig = ( - config: RollupOptions, - ...plugins: Array -): RollupOptions => ({ - plugins: [ - replace({ - values: { - DEV_PORT, - isDevMode: `${isDevMode}`, - 'process.env.NODE_ENV': isDevMode ? `'development'` : `'production'`, - }, - - preventAssignment: true, - }), - - nodeResolve({ browser: true, extensions: ['.js', '.ts', '.tsx'] }), - commonjs(), - css(), - - // isDevMode ? esbuild({ target: 'esnext', charset: 'utf8' }) : ts(), - // ts({ - // transpiler: 'babel', - // babelConfig: { - // presets: ['solid'], - // plugins: ['inline-react-svg'], - // }, - // transpileOnly: true, - // }), - babel({ - babelHelpers: 'runtime', - extensions: ['.ts', '.tsx'], - exclude: ['node_modules/**'], - presets: ['@babel/preset-env', '@babel/preset-typescript', 'solid'], - plugins: ['@babel/plugin-transform-runtime', 'inline-react-svg'], - }), - - ...plugins, - ], - external: [ - ...Object.keys(meta.resource ?? {}), - /\/helper$/, - // /@crs\/ui-component.*(? ({ - ...otherMeta, - - // 添加 xmlHttpRequest 权限 - grant: [...new Set([...grant, 'GM_xmlhttpRequest'])], - // 允许请求所有域 - connect: '*', - }))(meta), - }), - ], - }, - }, - del({ targets: 'dist/*' }), - isDevMode && - serve({ - contentBase: ['dist'], - port: DEV_PORT, - host: '127.0.0.1', - }), - ), - - // 单独打包每个站点的代码 - ...siteFileList.map((fileName) => - buildConfig({ - input: { [fileName.split('.')[0]]: `src/site/${fileName}` }, - output: { - dir: 'dist/cache', - format: 'cjs', - generatedCode: 'es2015', - exports: 'none', - strict: false, - inlineDynamicImports: true, - }, - context: 'this', - onwarn(warning, warn) { - // 禁用使用 eval 的警告 - if (warning.code !== 'EVAL') warn(warning); - }, - }), - ), - - buildConfig( - { - input: 'src/helper/index.ts', - output: { - file: 'dist/cache/helper.js', - format: 'cjs', - generatedCode: 'es2015', - strict: false, - plugins: [ - { - name: 'injectCode', - // 删掉 inline-react-svg 插入的 react 依赖 - renderChunk: (code) => code.replace(`require('react');\n`, ''), - }, - ], - }, - external: [...Object.keys(meta.resource ?? {})], - }, - // watchAssets({ assets: ['../ui-component/dist/*'] }), - ), - - // 生成自定义动态导入的代码 - buildConfig( - { - input: 'src/helper/import.ts', - output: { - file: 'dist/cache/import.js', - plugins: [ - { - name: 'injectCode', - renderChunk(code) { - let newCode = code; - // 将 ts 变量声明替换为 dist/cache 下的文件代码,并转为字符串型变量做好处理 - newCode = newCode.replace( - /const (\w+)Code = ['"]{2};(?=\n)/g, - (_, name) => - `const ${name}Code = \`\n${fs - .readFileSync(`./dist/cache/${name}.js`) - .toString() - .replaceAll('\\', '\\\\') - .replaceAll('`', '\\`') - .replaceAll('${', '\\${')}\`;\n`, - ); - return newCode; - }, - }, - ], - }, - }, - // watchAssets({ assets: ['dist/cache/helper.js'] }), - ), - - // 编译 index.user.js - { - input: 'src/index.tsx', - output: { - file: 'dist/index.user.js', - format: 'cjs', - generatedCode: 'es2015', - exports: 'none', - plugins: [ - { - name: 'injectSiteCode', - renderChunk(code) { - let newCode = code; - // 根据注释替换导入为 dist/cache 下的文件代码 - newCode = newCode.replace( - /(?<=\n)\s*\/\/ #(.+)(?=\n)/g, - (_, name) => - fs.readFileSync(`./dist/cache/${name}.js`)?.toString(), - ); - // 删除 export 语句 - newCode = newCode.replace(/\nexport.+};\n/g, ''); - // 在开发模式时计算下脚本的运行消耗时间 - if (isDevMode) - newCode = `console.time('脚本启动消耗时间')\n${newCode}\nconsole.timeEnd('脚本启动消耗时间')`; - return newCode; - }, - } as Plugin, - !isDevMode && - prettier({ - singleQuote: true, - trailingComma: 'all', - parser: 'babel', - }), - metablock({ file: '', override: meta }), - ], - }, - // plugins: [ - // watchAssets({ - // assets: ['dist/**/*', '!dist/index.user.js'], - // }), - // ], - treeshake: false, - }, -]; diff --git a/packages/userscript/src/components/Manga.tsx b/packages/userscript/src/components/Manga.tsx deleted file mode 100644 index 5c1ade52..00000000 --- a/packages/userscript/src/components/Manga.tsx +++ /dev/null @@ -1,83 +0,0 @@ -/* eslint-disable import/no-relative-packages */ -import type { MangaProps } from '@crs/ui-component/src'; -import { Manga } from '@crs/ui-component/src'; -import MangaStyle from '../../../ui-component/dist/Manga.css'; -import IconBottonStyle from '../../../ui-component/dist/IconButton.css'; -import { useComponentsRoot } from '../helper/utils'; - -export type SelfMangaProps = MangaProps & { - show: boolean; - handleExit: MangaProps['onExit']; -}; - -/** - * 显示漫画阅读窗口 - */ -export const useManga = async (initProps?: Partial) => { - const [render, dom] = useComponentsRoot('comicRead'); - await GM.addStyle(` - #comicRead > div { - position: fixed; - z-index: 999999999; - top: 0; - left: 0; - - width: 100vw; - height: 100vh; - - font-size: 16px; - - opacity: 1; - - transition: opacity 300ms, transform 100ms; - } - - #comicRead.hidden > div { - transform: scale(0); - - opacity: 0; - - transition: opacity 300ms, transform 0s 300ms; - } - `); - - const props = { imgList: [], show: false, ...initProps } as SelfMangaProps; - - const set = ( - recipe: - | Partial - | ((props: SelfMangaProps) => Partial), - onlyEdit = true, - ) => { - if (recipe) { - Object.assign( - props, - typeof recipe === 'function' ? recipe(props) : recipe, - ); - } - - if (onlyEdit) return; - - render(() => ( - <> - - - - - )); - - if (props.imgList.length && props.show) { - dom.className = ''; - document.documentElement.style.overflow = 'hidden'; - } else { - dom.className = 'hidden'; - document.documentElement.style.overflow = 'unset'; - } - }; - - props.onExit = () => { - set({ show: false }); - }; - - return [set, props] as [typeof set, SelfMangaProps]; -}; diff --git a/packages/userscript/src/components/Toast.tsx b/packages/userscript/src/components/Toast.tsx deleted file mode 100644 index 9109838b..00000000 --- a/packages/userscript/src/components/Toast.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import toast, { Toaster } from 'solid-toast'; -// eslint-disable-next-line import/no-cycle -import { useComponentsRoot } from '../helper/utils'; - -let mounted = false; - -export const useToast = () => { - if (!mounted) { - const [render] = useComponentsRoot('toast'); - render(() => ); - mounted = true; - } - - return toast; -}; diff --git a/packages/userscript/src/dev.ts b/packages/userscript/src/dev.ts deleted file mode 100644 index 6151965b..00000000 --- a/packages/userscript/src/dev.ts +++ /dev/null @@ -1,15 +0,0 @@ -GM_xmlhttpRequest({ - method: 'GET', - url: `http://127.0.0.1:${DEV_PORT as any}/index.user.js?${Date.now()}`, - timeout: 1000 * 5, - onload(r) { - if (r.status !== 200) - throw new Error(`${r.finalUrl}: ${r.status} ${r.statusText}`); - // eslint-disable-next-line no-eval - eval(`(async () => {${r.responseText}})();`); - }, - onerror: (e) => { - if (e.status === 0) throw new Error('dev server not running'); - throw new Error(String(e)); - }, -}); diff --git a/packages/userscript/src/helper/defaultSpeedDial.tsx b/packages/userscript/src/helper/defaultSpeedDial.tsx deleted file mode 100644 index 36d2750f..00000000 --- a/packages/userscript/src/helper/defaultSpeedDial.tsx +++ /dev/null @@ -1,60 +0,0 @@ -// import MdAutoStories from '@material-design-icons/svg/round/auto_stories.svg'; -import MdAutoFixHigh from '@material-design-icons/svg/round/auto_fix_high.svg'; -import MdAutoFixOff from '@material-design-icons/svg/round/auto_fix_off.svg'; -import MdAutoFlashOn from '@material-design-icons/svg/round/flash_on.svg'; -import MdAutoFlashOff from '@material-design-icons/svg/round/flash_off.svg'; - -import type { Component, JSX } from 'solid-js'; - -import { IconButton } from '@crs/ui-component/src'; -import type { DefaultOptions } from './useSiteOptions'; - -export const defaultSpeedDial = >( - options: T & DefaultOptions, - setOptions: ( - newValue: T & DefaultOptions, - trigger?: boolean, - ) => Promise, -) => { - const DefaultButton: Component<{ - optionName: string; - showName?: string; - children?: JSX.Element; - }> = (props) => { - return ( - - setOptions({ - ...options, - [props.optionName]: !options[props.optionName], - }) - } - > - {props.children ?? - (options[props.optionName] ? : )} - - ); - }; - - const list = Object.keys(options).map((optionName) => { - switch (optionName) { - case 'hiddenFAB': - case 'option': - return null; - - case 'autoShow': - return () => ( - - {options.autoShow ? : } - - ); - - default: - return () => ; - } - }); - - return list.filter(Boolean) as Array<() => JSX.Element>; -}; diff --git a/packages/userscript/src/helper/index.ts b/packages/userscript/src/helper/index.ts deleted file mode 100644 index 420ea506..00000000 --- a/packages/userscript/src/helper/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -export * from './utils'; -export * from './setToolbarButton'; -export * from './defaultSpeedDial'; -export * from './useCache'; -export * from './useInit'; -export * from './useSiteOptions'; -export * from '../components/Fab'; -export * from '../components/Manga'; -export * from '../components/Toast'; diff --git a/packages/userscript/src/helper/setToolbarButton.tsx b/packages/userscript/src/helper/setToolbarButton.tsx deleted file mode 100644 index 28dd0c18..00000000 --- a/packages/userscript/src/helper/setToolbarButton.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import MdFileDownload from '@material-design-icons/svg/round/file_download.svg'; -import MdClose from '@material-design-icons/svg/round/close.svg'; - -import { IconButton } from '@crs/ui-component/dist/IconButton'; -import { buttonListDivider } from '@crs/ui-component/dist/Manga'; - -import { createSignal } from 'solid-js'; -import fflate from 'fflate'; -import toast from 'solid-toast'; -import type { SelfMangaProps } from '../components/Manga'; -// eslint-disable-next-line import/no-cycle -import { request, saveAs } from './utils'; - -/** 为工具栏加上下载和退出按钮 */ -export const setToolbarButton = (draftProps: SelfMangaProps) => { - /** 下载按钮 */ - const DownloadButton = () => { - const [tip, setTip] = createSignal('下载'); - const handleDownload = async () => { - const { imgList } = draftProps; - - const fileData: fflate.Zippable = {}; - const imgIndexNum = `${imgList.length}`.length; - - for (let i = 0; i < imgList.length; i += 1) { - setTip(`下载中 - ${i}/${imgList.length}`); - const index = `${`${i}`.padStart(imgIndexNum, '0')}`; - const fileExt = imgList[i].split('.').at(-1)!; - const fileName = `${index}.${fileExt}`; - try { - // eslint-disable-next-line no-await-in-loop - const res = await request(imgList[i], { - responseType: 'arraybuffer', - }); - fileData[fileName] = new Uint8Array(res.response); - } catch (error) { - toast.error(`${fileName} 下载失败`); - fileData[`${index} - 下载失败.${fileExt}`] = new Uint8Array(); - } - } - - setTip('开始打包'); - const zipped = fflate.zipSync(fileData, { - level: 0, - comment: window.location.href, - }); - saveAs(new Blob([zipped]), `${document.title}.zip`); - setTip('下载完成'); - }; - - return ( - - - - ); - }; - - const handleEnd = () => draftProps.onExit?.(); - - draftProps.editButtonList = (list) => { - // 在设置按钮上方放置下载按钮 - list.splice(-1, 0, DownloadButton); - return [ - ...list, - // 再在最下面添加分隔栏和退出按钮 - buttonListDivider, - () => ( - - - - ), - ]; - }; - - return draftProps; -}; diff --git a/packages/userscript/src/helper/useInit.tsx b/packages/userscript/src/helper/useInit.tsx deleted file mode 100644 index 6122df60..00000000 --- a/packages/userscript/src/helper/useInit.tsx +++ /dev/null @@ -1,198 +0,0 @@ -/* eslint-disable import/no-cycle */ -import { useManga } from '../components/Manga'; -import { useFab } from '../components/Fab'; -import { useToast } from '../components/Toast'; -import { useSiteOptions } from './useSiteOptions'; -import { setToolbarButton } from './setToolbarButton'; -import { defaultSpeedDial } from './defaultSpeedDial'; -import { request } from './utils'; - -/** - * 对三个样式组件和 useSiteOptions 的默认值进行封装 - * - * @param name 站点名 - * @param defaultOptions 默认配置 - */ -export const useInit = async >( - name: string, - defaultOptions = {} as T, -) => { - const { options, setOptions, onOptionChange } = await useSiteOptions( - name, - defaultOptions, - ); - - const setFab = await useFab({ - tip: '阅读模式', - speedDial: defaultSpeedDial(options, setOptions), - }); - onOptionChange(() => setFab()); - - const [setManga, mangaProps] = await useManga({ - imgList: [], - option: options.option, - onOptionChange: (option) => setOptions({ ...options, option }), - }); - - const toast = useToast(); - - // 检查脚本的版本变化,提示用户 - const version = await GM.getValue('Version'); - if (version && version !== GM.info.script.version) { - // FIXME: 实现通过 jsdelivr 获取指定版本的更新内容 - // const changelog = ` - // ## 新增 - - // - 通过 M 键切换页面填充 - - // ## 修复 - - // - 增加拷贝漫画的支持域名 - // - 修复漫画柜失效问题 - // `; - (async () => { - // const res = await request( - // `https://cdn.jsdelivr.net/gh/hymbz/ComicReadScriptTest@${GM.info.script.version}/file`, - // { errorText: '' }, - // ); - // toast(() => ( - //
    - //

    ComicReadScrip 已更新到 {GM.info.script.version}

    - //
    - // {res.responseText.match(/##.+?\n|(-.+?\n)+/g)!.map((mdText) => { - // if (mdText[0] === '#') return

    {mdText.split('##')}

    ; - // if (mdText[0] === '-') - // return ( - //
      - // {mdText.match(/(?<=- ).+/g)!.map((item) => ( - //
    • {item}
    • - // ))} - //
    - // ); - // return null; - // })} - //
    - //
    - // )); - // GM_setValue('Version', GM.info.script.version); - })(); - } - - let menuId: number; - /** 更新显示/隐藏阅读模式按钮的菜单项 */ - const updateHideFabMenu = async () => { - await GM.unregisterMenuCommand(menuId); - menuId = await GM.registerMenuCommand( - `${options.hiddenFAB ? '显示' : '隐藏'}阅读模式按钮`, - async () => { - await setOptions({ ...options, hiddenFAB: !options.hiddenFAB }); - setFab((draftProps) => { - draftProps.show = !options.hiddenFAB && undefined; - }); - await updateHideFabMenu(); - }, - ); - }; - - return { - options, - setOptions, - onOptionChange, - setFab, - setManga, - toast, - - /** - * 完成所有支持站点的初始化 - * - * @param getImgList 返回图片列表的函数 - * @param onLoading 图片加载状态发生变化时触发的回调 - * @returns 自动加载图片并进入阅读模式的函数 - */ - init: ( - getImgList: () => Promise | string[], - onLoading: ( - loadNum: number, - totalNum: number, - img: ComicImg, - ) => void = () => {}, - ) => { - /** 是否正在加载图片中 */ - let loading = false; - - /** 进入阅读模式 */ - const showComic = async (show: boolean = options.autoShow) => { - if (loading) { - toast('加载图片中,请稍候', { - unmountDelay: 1500, - id: '加载图片中,请稍候', - }); - return; - } - - const { imgList } = mangaProps; - - if (!imgList.length) { - loading = true; - try { - setFab({ progress: 0, show: true }); - const initImgList = await getImgList(); - if (initImgList.length === 0) throw new Error('获取漫画图片失败'); - setFab({ - progress: 1, - tip: '阅读模式', - show: !options.hiddenFAB && undefined, - }); - setManga((draftProps) => { - draftProps.imgList = initImgList; - draftProps.show = show; - setToolbarButton(draftProps); - - // 监听图片加载状态,将进度显示到 Fab 上 - draftProps.onLoading = (img, list) => { - const loadNum = list.filter( - (image) => image.loadType === 'loaded', - ).length; - - onLoading(loadNum, list.length, img); - - /** 图片加载进度 */ - const progress = 1 + loadNum / list.length; - if (progress !== 2) { - setFab({ - progress, - tip: `图片加载中 - ${loadNum}/${list.length}`, - }); - } else { - // 图片全部加载完成后恢复 Fab 状态 - setFab({ progress, tip: '阅读模式', show: undefined }); - } - }; - - return draftProps; - }); - } catch (e: any) { - console.error(e); - toast.error(e.message); - setFab({ progress: undefined }); - } finally { - loading = false; - } - } else { - setManga({ show: true }); - } - }; - - setFab({ onClick: () => showComic(true) }); - // eslint-disable-next-line @typescript-eslint/no-floating-promises - if (options.autoShow) showComic(); - - // eslint-disable-next-line @typescript-eslint/no-floating-promises - GM.registerMenuCommand('进入漫画阅读模式', () => showComic(true)); - // eslint-disable-next-line @typescript-eslint/no-floating-promises - updateHideFabMenu(); - - return () => showComic(true); - }, - }; -}; diff --git a/packages/userscript/src/helper/useSiteOptions.ts b/packages/userscript/src/helper/useSiteOptions.ts deleted file mode 100644 index 74eecd22..00000000 --- a/packages/userscript/src/helper/useSiteOptions.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { MangaProps } from '@crs/ui-component/dist/Manga'; - -export interface DefaultOptions { - option: Partial | undefined; - - /** 自动进入阅读模式 */ - autoShow: boolean; - /** 隐藏 FAB */ - hiddenFAB: boolean; -} - -/** - * 对修改站点配置的相关方法的封装 - * - * @param name 站点名 - * @param defaultOptions 默认配置 - */ -export const useSiteOptions = async >( - name: string, - defaultOptions = {} as T, -) => { - type Options = T & DefaultOptions; - - const rawValue = await GM.getValue(name); - const options = Object.assign( - { - option: undefined, - autoShow: true, - hiddenFAB: false, - ...defaultOptions, - } as Options, - rawValue, - ); - - const changeCallbackList: ((options: Options) => void | Promise)[] = []; - - return { - options, - - /** 该站点是否有储存配置 */ - isRecorded: rawValue !== undefined, - - /** - * 设置新 Option - * - * @param newValue newValue - * @param trigger 是否触发变更事件 - */ - setOptions: async (newValue: Options, trigger = true) => { - Object.assign(options, newValue); - await GM.setValue(name, options); - if (trigger) - await Promise.all( - changeCallbackList.map((callback) => callback(options)), - ); - }, - - /** - * 监听配置变更事件 - */ - onOptionChange: (callback: (options: Options) => void | Promise) => { - changeCallbackList.push(callback); - }, - }; -}; diff --git a/packages/userscript/src/index.tsx b/packages/userscript/src/index.tsx deleted file mode 100644 index 96318c8a..00000000 --- a/packages/userscript/src/index.tsx +++ /dev/null @@ -1,8 +0,0 @@ -// #import - -// 匹配站点 -switch (window.location.hostname) { - default: { - // #test - } -} diff --git a/packages/userscript/src/site/copymanga.tsx b/packages/userscript/src/site/copymanga.tsx deleted file mode 100644 index f033c720..00000000 --- a/packages/userscript/src/site/copymanga.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { querySelectorClick, request, useInit } from '../helper'; - -(async () => { - // 只在漫画页内运行 - if (!window.location.href.includes('/chapter/')) return; - - const { setManga, init } = await useInit('copymanga'); - setManga({ - onNext: querySelectorClick('.comicContent-next a:not(.prev-null)'), - onPrev: querySelectorClick( - '.comicContent-prev:not(.index,.list) a:not(.prev-null)', - ), - }); - - init(async () => { - const res = await request( - window.location.href.replace( - /.*?(?=\/comic\/)/, - 'https://api.copymanga.site/api/v3', - ), - ); - - const { - results: { - chapter: { contents }, - }, - } = JSON.parse(res.responseText); - - type ContentsType = { url: string }[]; - return (contents as ContentsType).map(({ url }) => url); - }); -})(); diff --git a/packages/userscript/src/site/dmzj.tsx b/packages/userscript/src/site/dmzj.tsx deleted file mode 100644 index 307ed106..00000000 --- a/packages/userscript/src/site/dmzj.tsx +++ /dev/null @@ -1,219 +0,0 @@ -import { querySelectorClick, scrollIntoView, useInit } from '../helper'; -import { - insertNode, - querySelector, - querySelectorAll, - request, -} from '../helper/utils'; - -declare const g_comic_url: string; -declare const g_comic_id: string; -declare const $: any; - -// 解除吐槽的字数限制 功能部分引用的原代码使用到的变量 -declare const is_login: any; -declare const comicUrl: any; -declare const type: any; -declare const comic_id: any; -declare const chapter_id: any; -declare const uid: any; -declare const nickname: any; -declare const zcHtml: any; -declare const zcClick: any; - -(async () => { - // 某些隐藏漫画虽然被删掉了 PC 端页面,但其实手机版的网页依然还在 - // 所以当跳转至某部漫画的 PC 端页面被提示「页面找不到」时,就先跳转至手机版的页面去 - if (document.title === '页面找不到') { - // 测试例子:https://manhua.dmzj.com/yanquan/48713.shtml - const [, comicName, _chapter_id] = window.location.pathname.split(/[./]/); - const res = await request(`https://manhua.dmzj.com/${comicName}`); - - const _comic_id = /g_comic_id = "(\d+)/.exec(res.responseText)?.[1]; - if (!_comic_id) { - console.error('无法跳转至手机版页面', res); - // eslint-disable-next-line no-alert - alert('无法跳转至手机版页面'); - return; - } - - window.location.href = `https://m.dmzj.com/view/${_comic_id}/${_chapter_id}.html`; - return; - } - - // 通过 rss 链接,在作者作品页里添加上隐藏漫画的链接 - if (window.location.pathname.includes('/tags/')) { - const res = await request(querySelector('a.rss')!.href, { - errorText: '获取作者作品失败', - }); - - // 页面上原有的漫画标题 - const titleList = querySelectorAll('#hothit p.t').map((e) => - e.innerText.replace('[完]', ''), - ); - insertNode( - document.getElementById('hothit')!, - res.responseText - .split('item') - .filter((_, i) => i % 2) - .map((item) => { - const newComicUrl = /manhua.dmzj.com\/(.+?)\?from=rssReader/.exec( - item, - )![1]; - return { - newComicUrl, - comicUrl: newComicUrl.split('/')[0], - title: /title> !titleList.includes(title)) - .map( - (data) => ` - - `, - ) - .join(''), - ); - return; - } - - // 跳过漫画目录、漫画页外的其他页面 - if (!Reflect.has(unsafeWindow, 'g_comic_name')) return; - - if (!Reflect.has(unsafeWindow, 'g_chapter_name')) { - // 判断当前页是漫画详情页 - - // 判断漫画被禁 - // 测试例子:https://manhua.dmzj.com/yanquan/ - if (querySelector('.cartoon_online_border > img')) { - document.querySelector('.cartoon_online_border')!.innerHTML = - '正在加载中,请坐和放宽,若长时间无反应请刷新页面'; - - // XXX: 使用旧 api 只能获取到主版本的章节,其他版本的章节无法取得,改用 v4api 应该就能拿到了 - const res = await request( - `https://api.dmzj.com/dynamic/comicinfo/${g_comic_id}.json`, - { - errorText: '漫画加载出错', - }, - ); - - // 删掉原有的章节 dom - querySelectorAll('.odd_anim_title ~ div').forEach((e) => - e.parentNode?.removeChild(e), - ); - - const { - info: { last_updatetime, title }, - list: chaptersList, - } = JSON.parse(res.responseText).data as { - info: { - last_updatetime: string; - title: string; - }; - list: Array<{ - id: string; - chapter_name: string; - updatetime: string; - }>; - }; - - // 手动构建添加章节 dom - let temp = `

    ${title}

      `; - let i = chaptersList.length; - while (i--) { - temp += `
    • ${chaptersList[i].chapter_name}
    • `; - } - insertNode( - querySelector('.middleright_mr')!, - `${temp}
    `, - ); - } - return; - } - - // 处理当前页是漫画页的情况 - const { options, setManga, init, onOptionChange } = await useInit('dmzj', { - 解除吐槽的字数限制: true, - }); - - // 切换至上下翻页阅读 - if ($.cookie('display_mode') === '0') unsafeWindow.qiehuan(); - - // 根据漫画模式下的夜间模式切换样式 - if (options.option?.darkMode === false) { - document.body.classList.add('day'); - } - - onOptionChange((option) => { - // 监听漫画模式下的夜间模式切换,进行实时切换 - if (option.option?.darkMode) document.body.classList.remove('day'); - else document.body.classList.add('day'); - }); - - // 添加自定义样式修改 - await GM.addStyle(` - ${JSON.parse(await GM.getResourceText('dmzj_style')).sections[0].code} - - /* 修复和 dmzj_style 的冲突 */ - .mainNav { - display: none !important - } - - /* 增加日间模式的样式 */ - body.day { - background-color: white !important - } - body.day .header-box { - background-color: #DDD !important; - box-shadow: 0 1px 2px white - } - body.day .comic_gd_fb .gd_input { - color: #666; - background: white - } - `); - - setManga({ - onNext: querySelectorClick('#next_chapter'), - onPrev: querySelectorClick('#prev_chapter'), - onExit: (isEnd) => { - if (isEnd) { - unsafeWindow.huPoint(); - scrollIntoView('#hd'); - } - setManga({ show: false }); - }, - }); - - init( - () => - querySelectorAll('.inner_img img') - .map((e) => e.getAttribute('data-original')) - .filter((src) => src) as string[], - ); - - // 修改发表吐槽的函数,删去字数判断。只是删去了原函数的一个判断条件而已,所以将这段压缩了一下 - if (options.解除吐槽的字数限制) { - const intervalID = setInterval(() => { - if (!unsafeWindow.addpoint) return; - clearInterval(intervalID); - // eslint-disable-next-line - unsafeWindow.addpoint = function () { const e = $('#gdInput').val(); const c = $('input[name=length]').val(); if (e == '') { alert('沉默是你的个性,但还是吐个槽吧!'); return false; } else { if ($.trim(e) == '') { alert('空寂是你的个性,但还是吐个槽吧!'); return false; } } const d = $('#suBtn'); const b = d.attr('onclick'); const a = d.html(); d.attr('onclick', '').html('发表中..').css({ 'background': '#eee', 'color': '#999', 'cursor': 'not-allowed' }); if (is_login) { $.ajax({ type: 'get', url: `${comicUrl}/api/viewpoint/add`, dataType: 'jsonp', jsonp: 'callback', jsonpCallback: 'success_jsonpCallback_201508281119', data: `type=${type}&type_id=${comic_id}&chapter_id=${chapter_id}&uid=${uid}&nickname=${nickname}&title=${encodeURIComponent(e)}`, success: function (f) { if (f.result == 1000) { $('#gdInput').val(''); if ($('#moreLi').length > 0) { $('#moreLi').before(`
  • ${e}
  • `); } else { $('#tc').hide(); if (c == undefined) { $('.comic_gd_li').append(`
  • ${e}
  • `); } else { if (c > 9) { $('.comic_gd_li').append(`
  • ${e}
  • `); } else { $('.comic_gd_li').append(`
  • ${e}
  • `); } } } alert('吐槽成功'); } else { if (f.result == 2001) { $('body').append(zcHtml); zcClick(); } else { alert(f.msg); } } d.attr({ 'onclick': b, 'style': '' }).html(a); } }); } }; - }, 2000); - } -})(); diff --git a/packages/userscript/src/site/dmzj_phone.tsx b/packages/userscript/src/site/dmzj_phone.tsx deleted file mode 100644 index 72791bd2..00000000 --- a/packages/userscript/src/site/dmzj_phone.tsx +++ /dev/null @@ -1,171 +0,0 @@ -import { - insertNode, - querySelector, - querySelectorAll, - querySelectorClick, - request, - useInit, -} from '../helper'; - -// 接口参考 -// https://github.com/xiaoyaocz/flutter_dmzj/blob/ecbe73eb435624022ae5a77156c5d3e0c06809cc/lib/requests/api.dart -// https://github.com/erinacio/tachiyomi-extensions/blob/548be91cccb8f248342e2e7762c2c3d4b2d02036/src/zh/dmzj/src/eu/kanade/tachiyomi/extension/zh/dmzj/Dmzj.kt - -(async () => { - const { setManga, init } = await useInit('dmzj', { - 解除吐槽的字数限制: true, - }); - - // 分别处理目录页和漫画页 - switch (window.location.pathname.split('/')[1]) { - case 'info': { - // 跳过正常漫画 - if (Reflect.has(unsafeWindow, 'obj_id')) return; - - const comicId = parseInt(window.location.pathname.split('/')[2], 10); - if (Number.isNaN(comicId)) { - document.body.removeChild(document.body.childNodes[0]); - insertNode( - document.body, - ` - 请手动输入漫画名进行搜索
    -
    -
    - `, - ); - - querySelector('button')!.addEventListener('click', async () => { - const comicName = querySelector('input')?.value; - if (!comicName) return; - - const res = await request( - `https://s.acg.dmzj.com/comicsum/search.php?s=${comicName}`, - { errorText: '搜索漫画时出错' }, - ); - - const comicList = JSON.parse( - res.responseText.slice(20, -1), - ) as Array<{ - id: number; - comic_name: string; - comic_author: string; - comic_url: string; - }>; - - querySelector('#list')!.innerHTML = comicList - .map( - ({ id, comic_name, comic_author, comic_url }) => ` - 《${comic_name}》——${comic_author} - Web端 - 移动端 - `, - ) - .join('
    '); - }); - - return; - } - - // XXX: 使用旧 api 只能获取到主版本的章节,其他版本的章节无法取得,改用 v4api 应该就能拿到了 - const res = await request( - `http://api.dmzj.com/dynamic/comicinfo/${comicId}.json`, - { errorText: '获取漫画数据失败' }, - ); - - const { - info: { last_updatetime, title }, - list: chaptersList, - } = JSON.parse(res.responseText).data as { - info: { - last_updatetime: string; - title: string; - }; - list: Array<{ - id: string; - chapter_name: string; - updatetime: string; - }>; - }; - - document.title = title; - - let temp = `

    ${title}

    `; - let i = chaptersList.length; - while (i--) - temp += `${chaptersList[i].chapter_name}`; - insertNode(document.body, temp); - - document.body.removeChild(document.body.childNodes[0]); - await GM.addStyle( - 'body{padding:0 20vw;} a{margin:0 1em;line-height:2em;white-space:nowrap;display:inline-block;min-width:4em;}', - ); - break; - } - case 'view': { - // 如果不是隐藏漫画,直接进入阅读模式 - if (unsafeWindow.comic_id) { - await GM.addStyle('.subHeader{display:none !important}'); - setManga({ - onNext: querySelectorClick('#loadNextChapter'), - onPrev: querySelectorClick('#loadPrevChapter'), - }); - - const showComic = init( - () => - querySelectorAll('#commicBox img') - .map((e) => e.getAttribute('data-original')) - .filter((src) => src) as string[], - ); - await showComic(); - return; - } - - document.body.removeChild(document.body.childNodes[0]); - const tipDom = document.createElement('p'); - tipDom.innerText = '正在加载中,请坐和放宽,若长时间无反应请刷新页面'; - document.body.appendChild(tipDom); - - let res: Tampermonkey.Response; - - try { - res = await request( - `https://m.dmzj.com/chapinfo/${ - /\d+\/\d+/.exec(document.URL)![0] - }.html`, - { errorText: '获取漫画数据失败' }, - ); - } catch (error) { - tipDom.innerText = (error as Error).message; - throw error; - } - - tipDom.innerText = `加载完成,即将进入阅读模式`; - - const { folder, page_url } = JSON.parse(res.responseText) as { - folder: string; - page_url: string[]; - }; - document.title = folder.split('/').at(-2) ?? folder; - - // 进入阅读模式后禁止退出,防止返回空白页面 - setManga({ onExit: undefined, editButtonList: (list) => list }); - - const showComic = init(() => { - if (page_url.length) return page_url; - - tipDom.innerHTML = `无法获得漫画数据,请通过 GithubGreasy Fork 进行反馈`; - return []; - }); - await showComic(); - break; - } - } -})(); diff --git a/packages/userscript/src/site/dmzj_user_info.tsx b/packages/userscript/src/site/dmzj_user_info.tsx deleted file mode 100644 index 89eb2d12..00000000 --- a/packages/userscript/src/site/dmzj_user_info.tsx +++ /dev/null @@ -1,241 +0,0 @@ -import { querySelectorAll, insertNode, querySelector, saveAs } from '../helper'; - -/** - * 懒得整理导入导出的代码了,应该也没人用了吧,等有人需要的时候再说 - * 这里就先将代码搬过来放着,不能正常运行的话就重写 - */ - -declare const $: any; -declare const userId: string; - -/** - * 获取用户数据 - * - * @param dataType 数据类型 - * @param dom 用于在其上显示进度的按钮 - * @returns 用户数据 - */ -const getUserData = ( - dataType: string, - dom: HTMLElement, -): Promise< - { - name: string; - url: string; - id: string; - }[] -> => - new Promise((resolve, reject) => { - try { - // 取得尾页页数 - const pageNum = Number( - querySelectorAll('#page_id a[href^="#"]').at(-1)!.innerText, - ); - let loadPageNum = pageNum; - let returnHtml = ''; - const tipsDom = document.createElement('span'); - tipsDom.className = 'mess_num'; - dom.parentNode!.appendChild(tipsDom); - - for (let i = 0; i <= pageNum; i++) { - $.ajax({ - url: `/ajax/my/${dataType}`, - type: 'POST', - data: { - page: i, - type_id: 1, - letter_id: 0, - read_id: 1, - }, - }) - // eslint-disable-next-line no-loop-func - .done((data: string) => { - returnHtml += data; - loadPageNum -= 1; - tipsDom.innerText = `${pageNum - loadPageNum}/${pageNum}`; - if (!loadPageNum) { - const tempDom = document.createElement('div'); - tempDom.innerHTML = returnHtml; - resolve( - [...tempDom.getElementsByClassName('his_li')].map((e) => { - const aList = e.getElementsByTagName('a'); - return { - name: aList[1].innerText, - url: aList[0].href, - id: aList[aList.length - 1].id.split('_')[1], - }; - }), - ); - } - }); - } - } catch (error) { - reject(error); - } - }); - -(async () => { - if ( - window.location.pathname.includes('subscribe') && - document.querySelector('#yc1.optioned') - ) { - await GM.addStyle( - '.sub_center_con{position: relative;}#script{position: absolute;right: 0;top: 0;border-width: 1px;border-color: #e6e6e6;border-top-style: solid;border-left-style: solid;cursor: pointer;}#importDetails .account_btm_cont p{margin: 1em 0;}', - ); - insertNode( - querySelector('.sub_potion')!, - ` -
    -
  • - - -
  • -
  • - -
  • -
    - `, - ); - - const importDom = document.getElementById('scriptImport')!; - const exportDom = document.getElementById('scriptExpor')!; - - exportDom.addEventListener('click', () => { - const subscriptionData = [ - ...document.getElementsByClassName('dy_content_li'), - ].map((e) => { - const aList = e.getElementsByTagName('a'); - return { - name: aList[1].innerText, - url: aList[0].href, - id: aList[aList.length - 1].getAttribute('value'), - }; - }); - saveAs( - new Blob([JSON.stringify(subscriptionData, null, 4)], { - type: 'text/plain;charset=utf-8', - }), - '动漫之家订阅信息.json', - ); - }); - - importDom.addEventListener('change', async (e) => { - if ((e.target! as HTMLInputElement).files!.length) { - const serverSubscriptionData = await getUserData( - 'subscribe', - exportDom, - ); - - const reader = new FileReader(); - reader.onload = (event) => { - const loadDom = document.createElement('span'); - // 导入文件的订阅数据 - const subscriptionData = JSON.parse(event.target!.result as string); - // 需要订阅的漫画数据 - const needSubscribeList = subscriptionData.filter( - (data: any) => - !serverSubscriptionData.map(({ id }) => id).includes(data.id), - ) as { name: string; id: string }[]; - const needSubscribeNum = needSubscribeList.length; - - if (needSubscribeNum) { - let subscribeIndex = needSubscribeNum - 1; - - loadDom.className = 'mess_num'; - importDom.parentNode!.appendChild(loadDom); - - const subscribe = () => { - $.ajax({ - url: 'https://interface.dmzj.com/api/subscribe/add', - type: 'get', - jsonp: 'callback', - data: { - sub_id: needSubscribeList[subscribeIndex].id, - uid: userId, - sub_type: 0, - }, - dataType: 'jsonp', - jsonpCallback: 'success', - error: () => { - subscribe(); - }, - success: (data: any) => { - // 1000:成功订阅, 809:已订阅 - if (data.result !== 1000 && data.result !== 809) - throw new Error(`订阅返回值:${data.result}`); - if (subscribeIndex) { - loadDom.innerText = `${--subscribeIndex}`; - subscribe(); - } else { - loadDom.parentNode!.removeChild(loadDom); - insertNode( - document.body, - ` -
    -
    -
    - - -
    - -
    -
    -
    - `, - ); - querySelector( - '#importDetails .account_close', - )?.addEventListener('click', (clickEvent) => { - document.body.removeChild((clickEvent as any).path[3]); - }); - } - }, - }); - }; - subscribe(); - } - // eslint-disable-next-line no-alert - else alert(`导入 ${subscriptionData.length} 部漫画数据,均已订阅`); - }; - reader.readAsText((e.target! as HTMLInputElement).files![0]); - } - }); - } else if ( - window.location.pathname.includes('record') && - document.querySelector('#yc1.optioned') - ) { - await GM.addStyle( - '.sub_center_con{position: relative;}#script{position: absolute;right: 0;top: 0;border-width: 1px;border-color: #e6e6e6;border-top-style: solid;border-left-style: solid;cursor: pointer;}#importDetails .account_btm_cont p{margin: 1em 0;}', - ); - insertNode( - querySelector('.inter_con_h')!, - `导出`, - ); - - const exportDom = document.getElementById('scriptExpor')!; - - exportDom.addEventListener('click', async () => { - const recordData = await getUserData('record', exportDom); - - saveAs( - new Blob([JSON.stringify(recordData, null, 4)], { - type: 'text/plain;charset=utf-8', - }), - '动漫之家云端历史记录.json', - ); - }); - } -})(); diff --git a/packages/userscript/src/site/dmzj_www.tsx b/packages/userscript/src/site/dmzj_www.tsx deleted file mode 100644 index 15a2bcde..00000000 --- a/packages/userscript/src/site/dmzj_www.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { querySelectorClick, useInit } from '../helper'; - -declare const picArry: string[]; -declare const img_prefix: string; - -(async () => { - // 只在漫画页内运行 - if (!Reflect.has(unsafeWindow, 'g_comic_id')) return; - - const { setManga, init } = await useInit('dmzj'); - setManga({ - onNext: querySelectorClick('.next > a'), - onPrev: querySelectorClick('.pre > a'), - }); - - init(() => picArry.map((url) => `${img_prefix}${url}`)); -})(); diff --git a/packages/userscript/src/site/ehentai.tsx b/packages/userscript/src/site/ehentai.tsx deleted file mode 100644 index 0338db5a..00000000 --- a/packages/userscript/src/site/ehentai.tsx +++ /dev/null @@ -1,294 +0,0 @@ -import { - insertNode, - linstenKeyup, - querySelector, - scrollIntoView, - request, - useInit, -} from '../helper'; - -declare const selected_tag: string; -declare const selected_link: HTMLElement; - -(async () => { - const { options, setFab, setManga, init, toast } = await useInit('nhentai', { - 匹配nhentai: true, - 快捷键翻页: true, - }); - - // 不是漫画页的话 - if (!Reflect.has(unsafeWindow, 'gid')) { - if (options.快捷键翻页) { - linstenKeyup((e) => { - switch (e.key) { - case 'ArrowRight': - case 'd': - querySelector('#dnext')?.click(); - break; - - case 'ArrowLeft': - case 'a': - querySelector('#dprev')?.click(); - break; - } - }); - } - return; - } - - setManga({ - onExit: (isEnd) => { - if (isEnd) scrollIntoView('#cdiv'); - setManga({ show: false }); - }, - }); - - // 虽然有 Fab 了不需要这个按钮,但都点习惯了没有还挺别扭的( - insertNode( - document.getElementById('gd5')!, - '

    Load comic

    ', - ); - const comicReadModeDom = document.getElementById('comicReadMode')!; - - const totalImgNum = parseInt( - querySelector('#gdd > table > tbody > tr:nth-child(6) > td.gdt2')! - .innerHTML, - 10, - ); - let loadedImgNum = 0; - - /** - * 从图片页获取图片地址 - */ - const getImgFromImgPage = async (url: string): Promise => { - const res = await request(url, { - errorText: '从图片页获取图片地址失败', - }); - - loadedImgNum += 1; - setFab({ - progress: loadedImgNum / totalImgNum, - tip: `加载图片中 - ${loadedImgNum}/${totalImgNum}`, - }); - comicReadModeDom.innerHTML = ` loading image - ${loadedImgNum}/${totalImgNum}`; - - return res.responseText.split('id="img" src="')[1].split('"')[0]; - }; - - /** 从详情页获取图片页的地址的正则 */ - const getImgFromDetailsPageRe = - /(?<=\d+ => { - const res = await request( - `${window.location.origin}${window.location.pathname}${ - pageNum ? `?p=${pageNum}` : '' - }`, - { - errorText: '从详情页获取图片页地址失败', - }, - ); - - // 从详情页获取图片页的地址 - const imgPageList = res.responseText.match( - getImgFromDetailsPageRe, - ) as string[]; - if (imgPageList === null) throw new Error('从详情页获取图片页的地址时出错'); - - return Promise.all(imgPageList.map(getImgFromImgPage)); - }; - - const showComic = init( - async () => { - const totalPageNum = +querySelector('.ptt td:nth-last-child(2)')! - .innerText; - - const taskList = [...Array(totalPageNum).keys()]; - const resList: string[][] = []; - - const work = async (): Promise => { - const pageNum = taskList.pop(); - if (pageNum === undefined) return undefined; - resList[pageNum] = await getImgFromDetailsPage(pageNum); - return work(); - }; - - // 双线程抓图 - await Promise.all([work(), work()]); - return resList.flat(); - }, - (loadNum, totalNum) => { - comicReadModeDom.innerHTML = - loadNum !== totalNum - ? ` image loading - ${loadNum}/${totalNum}` - : ' Read'; - }, - ); - setFab({ initShow: options.autoShow }); - comicReadModeDom.addEventListener('click', showComic); - - if (options.快捷键翻页) { - linstenKeyup((e) => { - switch (e.key) { - case 'ArrowRight': - case 'd': - querySelector('.ptt td:last-child:not(.ptdd)')?.click(); - break; - - case 'ArrowLeft': - case 'a': - querySelector('.ptt td:first-child:not(.ptdd)')?.click(); - break; - } - }); - } - - if (options.匹配nhentai) { - const titleDom = document.getElementById('gn'); - const taglistDom = querySelector('#taglist tbody'); - if (!titleDom || !taglistDom) { - toast.error('页面结构发生改变,匹配 nhentai 漫画功能无法正常生效'); - return; - } - - const newTagLine = document.createElement('tr'); - - let res: Tampermonkey.Response; - try { - res = await request( - `https://nhentai.net/api/galleries/search?query=${encodeURI( - titleDom.innerText, - )}`, - { errorText: '' }, - ); - } catch (_) { - newTagLine.innerHTML = ` - nhentai: - - 匹配失败,请确认 nhentai 登录状态 - `; - taglistDom.appendChild(newTagLine); - return; - } - - const nHentaiComicInfo = JSON.parse(res.responseText) as { - result: Array<{ - id: number; - media_id: string; - num_pages: number; - images: { pages: Array<{ t: string }> }; - title: { japanese: string; english: string }; - }>; - }; - - // 构建新标签行 - if (nHentaiComicInfo.result.length) { - let temp = 'nhentai:'; - let i = nHentaiComicInfo.result.length; - while (i) { - i -= 1; - const tempComicInfo = nHentaiComicInfo.result[i]; - temp += ``; - } - newTagLine.innerHTML = `${temp}`; - } else - newTagLine.innerHTML = - 'nhentai:Null'; - - taglistDom.appendChild(newTagLine); - - // 重写 _refresh_tagmenu_act 函数,加入脚本的功能 - const nhentaiImgList: Record = {}; - unsafeWindow._refresh_tagmenu_act = function _refresh_tagmenu_act( - a: any, - b: any, - ) { - const tagmenu_act_dom = document.getElementById('tagmenu_act')!; - if (a.includes('nhentai:')) { - tagmenu_act_dom.innerHTML = `> Jump to nhentai`; - - tagmenu_act_dom.innerHTML += `> ${ - nhentaiImgList[selected_tag] ? 'Read' : 'Load comic' - }`; - const nhentaiComicReadModeDom = - tagmenu_act_dom.querySelector('a[href="#"]')!; - - // 加载 nhentai 漫画 - nhentaiComicReadModeDom.addEventListener('click', async (e) => { - e.preventDefault(); - const comicInfo = - nHentaiComicInfo.result[+selected_link.getAttribute('index')!]; - let loadNum = 0; - - if (!nhentaiImgList[selected_tag]) { - nhentaiComicReadModeDom.innerHTML = ` loading - ${loadNum}/${comicInfo.num_pages}`; - // 用于转换获得图片文件扩展名的 dict - const fileType = { - j: 'jpg', - p: 'png', - g: 'gif', - }; - - nhentaiImgList[selected_tag] = await Promise.all( - comicInfo.images.pages.map(async ({ t }, i) => { - const imgRes = await request( - `https://i.nhentai.net/galleries/${comicInfo.media_id}/${ - i + 1 - }.${fileType[t]}`, - { - headers: { - Referer: `https://nhentai.net/g/${comicInfo.media_id}`, - }, - responseType: 'blob', - }, - ); - const blobUrl = URL.createObjectURL(imgRes.response); - loadNum += 1; - nhentaiComicReadModeDom.innerHTML = ` loading - ${loadNum}/${comicInfo.num_pages}`; - return blobUrl; - }), - ); - nhentaiComicReadModeDom.innerHTML = ' Read'; - } - setManga({ imgList: nhentaiImgList[selected_tag], show: true }); - }); - } else { - const mr = - '>'; - let temp = ''; - if (b.className !== 'tup') - temp += ` ${mr} ${ - b.className === '' ? 'Vote Up' : 'Withdraw Vote' - }`; - if (b.className !== 'tdn') - temp += ` ${mr} ${ - b.className === '' ? 'Vote Down' : 'Withdraw Vote' - }`; - // 删掉原有的 Show Tagged Galleries 按钮空出位置 - temp += `${mr} Show Tag Definition${mr} Add New Tag ${mr} `; - - const tag = selected_link.id.slice(3).split(':'); - if (tag.length === 1) { - temp += `Jump to nhentai`; - } else { - temp += `Jump to nhentai`; - } - tagmenu_act_dom.innerHTML = temp; - } - }; - } -})(); diff --git a/packages/userscript/src/site/jm.tsx b/packages/userscript/src/site/jm.tsx deleted file mode 100644 index c2829de6..00000000 --- a/packages/userscript/src/site/jm.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { request, plimit, querySelectorAll, sleep, useInit } from '../helper'; - -(async () => { - // 只在漫画页内运行 - if (!window.location.pathname.includes('/photo/')) return; - - const { init, setFab, toast } = await useInit('jm'); - - while (!unsafeWindow?.onImageLoaded) { - if (document.readyState === 'complete') { - toast.error('无法获取图片', { autoClose: false }); - return; - } - // eslint-disable-next-line no-await-in-loop - await sleep(100); - } - - const imgEleList = querySelectorAll('.scramble-page > img'); - - // 判断当前漫画是否有被分割,没有就直接获取图片链接加载 - // 判断条件来自页面上的 scramble_image 函数 - if ( - unsafeWindow.aid < unsafeWindow.scramble_id || - unsafeWindow.speed === '1' - ) { - init(() => imgEleList.map((e) => e.getAttribute('data-original')!)); - return; - } - - const getImgUrl = async (imgEle: HTMLImageElement) => { - const res = await request(imgEle.getAttribute('data-original')!, { - responseType: 'blob', - }); - imgEle.src = URL.createObjectURL(res.response); - await new Promise((resolve, reject) => { - imgEle.onload = resolve; - imgEle.onerror = reject; - }); - unsafeWindow.onImageLoaded(imgEle); - const blob = await new Promise((resolve) => { - (imgEle.nextElementSibling as HTMLCanvasElement).toBlob( - resolve, - 'image/webp', - 1, - ); - }); - if (!blob) return ''; - return `${URL.createObjectURL(blob)}#.webp`; - }; - - init(() => - plimit( - 10, - imgEleList.map((img) => async () => getImgUrl(img)), - (resList) => { - setFab({ - progress: resList.length / imgEleList.length, - tip: `加载图片中 - ${resList.length}/${imgEleList.length}`, - }); - }, - ), - ); -})(); diff --git a/packages/userscript/src/site/mangabz.tsx b/packages/userscript/src/site/mangabz.tsx deleted file mode 100644 index 2b7f6b6d..00000000 --- a/packages/userscript/src/site/mangabz.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { dataToParams, querySelectorClick, request, useInit } from '../helper'; - -// 页面自带的变量 -declare const MANGABZ_CID: number; -declare const MANGABZ_MID: number; -declare const MANGABZ_VIEWSIGN_DT: string; -declare const MANGABZ_VIEWSIGN: string; -declare const MANGABZ_COOKIEDOMAIN: string; -declare const MANGABZ_CURL: string; -/** 总页数 */ -declare const MANGABZ_IMAGE_COUNT: number; - -(async () => { - // 只在漫画页内运行 - if (!Reflect.has(unsafeWindow, 'MANGABZ_CID')) return; - - const { setFab, setManga, init } = await useInit('mangabz'); - - setManga({ - onNext: querySelectorClick('body > .container a[href^="/"]:last-child'), - onPrev: querySelectorClick('body > .container a[href^="/"]:first-child'), - }); - - const getImgList = async (imgList: string[] = []): Promise => { - const urlParams = dataToParams({ - cid: MANGABZ_CID, - page: imgList.length + 1, - key: '', - _cid: MANGABZ_CID, - _mid: MANGABZ_MID, - _dt: MANGABZ_VIEWSIGN_DT.replace(' ', '+').replace(':', '%3A'), - _sign: MANGABZ_VIEWSIGN, - }); - - const res = await request( - `http://${MANGABZ_COOKIEDOMAIN}${MANGABZ_CURL}chapterimage.ashx?${urlParams}`, - ); - - // 返回的数据只能通过 eval 获得 - // eslint-disable-next-line no-eval - const newImgList = [...imgList, ...(eval(res.responseText) as string[])]; - - if (newImgList.length !== MANGABZ_IMAGE_COUNT) { - // 在 Fab 按钮上通过进度条和提示文本显示当前进度 - setFab({ - progress: newImgList.length / MANGABZ_IMAGE_COUNT, - tip: `加载图片中 - ${newImgList.length}/${MANGABZ_IMAGE_COUNT}`, - }); - return getImgList(newImgList); - } - - return newImgList; - }; - - init(getImgList); -})(); diff --git a/packages/userscript/src/site/manhuaDB.tsx b/packages/userscript/src/site/manhuaDB.tsx deleted file mode 100644 index 4702c2b1..00000000 --- a/packages/userscript/src/site/manhuaDB.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { dataToParams, querySelectorClick, useInit } from '../helper'; - -declare const img_data_arr: { img: string }[]; -declare const img_host: string; -declare const img_pre: string; -declare const p_ccid: number; -declare const p_id: number; -declare const p_d: number; -declare const vg_r_data: any; -declare const $: any; - -(async () => { - // 只在漫画页内运行 - if (!Reflect.has(unsafeWindow, 'img_data_arr')) return; - - const { setManga, init } = await useInit('manhuaDB'); - - /** - * 检查是否有上/下一话 - */ - const checkTurnPage = async (type: 'pre' | 'next') => { - const res = await $.ajax({ - method: 'POST', - url: '/book/goNumPage', - dataType: 'json', - data: dataToParams({ - ccid: p_ccid, - id: p_id, - num: (vg_r_data.data('num') as number) + (type === 'next' ? 1 : -1), - d: p_d, - type, - }), - }); - - if (res.state) - return querySelectorClick( - `a[title="${type === 'next' ? '下集' : '上集'}"]`, - ); - - return null; - }; - setManga({ - onNext: await checkTurnPage('next'), - onPrev: await checkTurnPage('pre'), - }); - - init(() => img_data_arr.map((data) => `${img_host}/${img_pre}/${data.img}`)); -})(); diff --git a/packages/userscript/src/site/manhuacat.tsx b/packages/userscript/src/site/manhuacat.tsx deleted file mode 100644 index 6fb2589c..00000000 --- a/packages/userscript/src/site/manhuacat.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { useInit } from '../helper'; - -declare const img_data_arr: string[]; -declare const img_pre: string; -declare const asset_domain: string; -declare const asset_key: string; -declare const chapter_num: number; -declare const chapter_type: number; -declare const cdnImage: (a: string, b: string, c: string) => string; -declare const goNumPage: (a: string) => void; -declare const $: any; - -(async () => { - // 只在漫画页内运行 - if (!Reflect.has(unsafeWindow, 'cdnImage')) return; - - const { setManga, init } = await useInit('manhuacat'); - - /** - * 检查是否有上/下一页 - */ - const checkTurnPage = async (type: 'pre' | 'next') => { - const res = await $.ajax({ - type: 'get', - url: `/chapter_num?chapter_id=${chapter_num}&ctype=${ - type === 'next' ? 1 : 2 - }&type=${chapter_type}`, - dataType: 'json', - }); - - if (res.code === '0000') return () => goNumPage(type); - - return null; - }; - setManga({ - onNext: await checkTurnPage('next'), - onPrev: await checkTurnPage('pre'), - }); - - init(() => - img_data_arr.map((img) => cdnImage(img_pre + img, asset_domain, asset_key)), - ); -})(); diff --git a/packages/userscript/src/site/manhuagui.tsx b/packages/userscript/src/site/manhuagui.tsx deleted file mode 100644 index 445c0c6e..00000000 --- a/packages/userscript/src/site/manhuagui.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { querySelectorClick, useInit } from '../helper'; - -declare const pVars: { manga: { filePath: string } }; -declare const cInfo: { nextId: number; prevId: number }; - -(async () => { - // 只在漫画页内运行 - if (!Reflect.has(unsafeWindow, 'cInfo')) return; - - const { setManga, init } = await useInit('manhuagui'); - setManga({ - onNext: cInfo.nextId !== 0 ? querySelectorClick('a.nextC') : null, - onPrev: cInfo.prevId !== 0 ? querySelectorClick('a.prevC') : null, - }); - - init(() => { - const comicInfo = JSON.parse( - // 只能通过 eval 获得数据 - // eslint-disable-next-line no-eval - eval( - document.querySelectorAll('body > script')[1].innerHTML.slice(26), - ).slice(12, -12), - ); - const sl = Object.entries(comicInfo.sl) - .map((attr) => `${attr[0]}=${attr[1]}`) - .join('&'); - return (comicInfo.files as string[]).map( - (file) => `${pVars.manga.filePath}${file}?${sl}`, - ); - }); -})(); diff --git a/packages/userscript/src/site/newYamibo.tsx b/packages/userscript/src/site/newYamibo.tsx deleted file mode 100644 index 9562a1a9..00000000 --- a/packages/userscript/src/site/newYamibo.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { - querySelector, - querySelectorClick, - request, - scrollIntoView, - useInit, -} from '../helper'; - -(async () => { - // 只在漫画页内运行 - if (!document.URL.includes('view-chapter')) return; - - const { setFab, setManga, init } = await useInit('newYamibo'); - - setManga({ - onNext: querySelectorClick('#btnNext'), - onPrev: querySelectorClick('#btnPrev'), - onExit: (isEnd) => { - if (isEnd) scrollIntoView('#w1'); - setManga({ show: false }); - }, - }); - - const id = new URLSearchParams(window.location.search).get('id'); - /** 总页数 */ - const totalNum = +querySelector( - 'section div:first-of-type div:last-of-type', - )!.innerHTML.split(':')[1]; - - const getImgList = async ( - i = 1, - imgList: string[] = [], - ): Promise => { - const res = await request( - `https://www.yamibo.com/manga/view-chapter?id=${id}&page=${i}`, - ); - - imgList.push( - // - .exec(res.responseText)![1] - .replaceAll('&', '&'), - ); - - if (imgList.length === totalNum) { - setFab({ progress: 1, tip: '阅读模式' }); - return imgList; - } - - setFab({ - progress: imgList.length / totalNum, - tip: `加载图片中 - ${imgList.length}/${totalNum}`, - }); - - return getImgList(i + 1, imgList); - }; - - init(getImgList); -})(); diff --git a/packages/userscript/src/site/nhentai.tsx b/packages/userscript/src/site/nhentai.tsx deleted file mode 100644 index 1a93ca1d..00000000 --- a/packages/userscript/src/site/nhentai.tsx +++ /dev/null @@ -1,222 +0,0 @@ -import { - insertNode, - querySelector, - querySelectorAll, - request, - scrollIntoView, - useInit, -} from '../helper'; - -/** 用于转换获得图片文件扩展名 */ -const fileType = { - j: 'jpg', - p: 'png', - g: 'gif', -}; - -type Images = { - thumbnail: { h: number; w: number; t: keyof typeof fileType }; - pages: { number: number; extension: string }[]; -}; -declare const gallery: { num_pages: number; media_id: string; images: Images }; - -(async () => { - const { options, setFab, setManga, toast, init } = await useInit('nhentai', { - 自动翻页: true, - 彻底屏蔽漫画: true, - 在新页面中打开链接: true, - }); - - // 在漫画详情页 - if (Reflect.has(unsafeWindow, 'gallery')) { - setManga({ - onExit: (isEnd) => { - if (isEnd) scrollIntoView('#comment-container'); - setManga({ show: false }); - }, - }); - - // 虽然有 Fab 了不需要这个按钮,但我自己都点习惯了没有还挺别扭的( - insertNode( - document.getElementById('download')!.parentNode as HTMLElement, - ' Load comic', - ); - const comicReadModeDom = document.getElementById('comicReadMode')!; - const showComic = init( - () => - gallery.images.pages.map( - ({ number, extension }) => - `https://i.nhentai.net/galleries/${gallery.media_id}/${number}.${extension}`, - ), - (loadNum, totalNum) => { - comicReadModeDom.innerHTML = - loadNum !== totalNum - ? ` loading —— ${loadNum}/${totalNum}` - : ' Read'; - }, - ); - setFab({ initShow: options.autoShow }); - comicReadModeDom.addEventListener('click', showComic); - - return; - } - - // 在漫画浏览页 - if (document.getElementsByClassName('gallery').length) { - if (options.在新页面中打开链接) - querySelectorAll('a:not([href^="javascript:"])').forEach((e) => - e.setAttribute('target', '_blank'), - ); - - const blacklist: number[] = (unsafeWindow?._n_app ?? unsafeWindow?.n) - ?.options?.blacklisted_tags; - if (blacklist === undefined) toast.error('标签黑名单获取失败'); - // blacklist === null 时是未登录 - - if (options.彻底屏蔽漫画 && blacklist?.length) - await GM.addStyle('.blacklisted.gallery { display: none; }'); - - if (options.自动翻页) { - await GM.addStyle(` - hr { bottom: 0; box-sizing: border-box; margin: -1em auto 2em; } - hr:last-child { position: relative; animation: load .8s linear alternate infinite; } - hr:not(:last-child) { display: none; } - @keyframes load { 0% { width: 100%; } 100% { width: 0; } } - `); - let pageNum = Number(querySelector('.page.current')?.innerHTML ?? ''); - if (Number.isNaN(pageNum)) return; - - let loadLock = !pageNum; - const contentDom = document.getElementById('content')!; - const apiUrl = (() => { - if (window.location.pathname === '/') - return 'https://nhentai.net/api/galleries/all?'; - if (querySelector('a.tag')) - return `https://nhentai.net/api/galleries/tagged?tag_id=${ - querySelector('a.tag')?.classList[1].split('-')[1] - }&`; - if (window.location.pathname.includes('search')) - return `https://nhentai.net/api/galleries/search?query=${new URLSearchParams( - window.location.search, - ).get('q')}&`; - return ''; - })(); - - const loadNewComic = async (): Promise => { - if ( - loadLock || - contentDom.lastElementChild!.getBoundingClientRect().top > - window.innerHeight - ) - return undefined; - - loadLock = true; - pageNum += 1; - const res = await request( - `${apiUrl}page=${pageNum}${ - window.location.pathname.includes('popular') ? '&sort=popular ' : '' - }`, - { errorText: '下一页漫画信息加载出错' }, - ); - - const { result, num_pages } = JSON.parse(res.responseText) as { - num_pages: number; - result: { - id: number; - media_id: string; - tags: { id: number }[]; - title: { english: string }; - images: Images; - }[]; - }; - - let comicDomHtml = ''; - - // 在 用户已登录 且 有设置标签黑名单 且 开启了彻底屏蔽功能时,才对结果进行筛选 - (options.彻底屏蔽漫画 && blacklist?.length - ? result.filter(({ tags }) => - tags.every((tag) => !blacklist.includes(tag.id)), - ) - : result - ).forEach((comic) => { - comicDomHtml += ``; - }); - - // 构建页数按钮 - if (comicDomHtml) { - const target = options.在新页面中打开链接 ? 'target="_blank" ' : ''; - const pageNumDom: string[] = []; - for (let i = pageNum - 5; i <= pageNum + 5; i += 1) { - if (i > 0 && i <= num_pages) - pageNumDom.push( - `${i}`, - ); - } - - insertNode( - contentDom, - `

    ${pageNum}

    -
    ${comicDomHtml}
    -
    - - - - - - ${pageNumDom.join('')} - ${ - pageNum === num_pages - ? '' - : ` - - - - ` - } -
    `, - ); - } - - // 添加分隔线 - contentDom.appendChild(document.createElement('hr')); - if (pageNum < num_pages) loadLock = false; - else - ( - contentDom.lastElementChild as HTMLElement - ).style.animationPlayState = 'paused'; - - // 当前页的漫画全部被屏蔽或当前显示的漫画少到连滚动条都出不来时,继续加载 - if ( - !comicDomHtml || - contentDom.offsetHeight < document.body.offsetHeight - ) - return loadNewComic(); - - return undefined; - }; - - window.addEventListener('scroll', loadNewComic); - if (querySelector('section.pagination')) - contentDom.appendChild(document.createElement('hr')); - await loadNewComic(); - } - } -})(); diff --git a/packages/userscript/src/site/other.tsx b/packages/userscript/src/site/other.tsx deleted file mode 100644 index fb3a1ddc..00000000 --- a/packages/userscript/src/site/other.tsx +++ /dev/null @@ -1,125 +0,0 @@ -import { - useManga, - useFab, - useToast, - setToolbarButton, - defaultSpeedDial, - isEqualArray, -} from '../helper'; -import type { AsyncReturnType } from '../helper/utils'; -import { useSiteOptions } from '../helper/useSiteOptions'; - -setTimeout(async () => { - const { options, setOptions, isRecorded, onOptionChange } = - await useSiteOptions(window.location.hostname, { autoShow: false }); - - /** 图片列表 */ - let imgList: string[] = []; - /** 是否正在后台不断检查图片 */ - let running = 0; - - let setManga: AsyncReturnType[0]; - let setFab: AsyncReturnType; - let toast: ReturnType; - - const init = async () => { - if (setManga !== undefined) return; - - [setManga] = await useManga({ - imgList, - show: options.autoShow, - onOptionChange: (option) => setOptions({ ...options, option }, false), - }); - setManga(setToolbarButton, false); - - setFab = await useFab({ - tip: '阅读模式', - onClick: () => setManga({ show: true }), - speedDial: defaultSpeedDial(options, setOptions), - }); - onOptionChange(() => setFab!()); - setFab!(); - - toast = useToast(); - }; - - /** 已经被触发过懒加载的图片 */ - const triggedImgList: Set = new Set(); - /** 触发懒加载 */ - const triggerLazyLoad = () => { - const targetImgList = [...document.getElementsByTagName('img')] - // 过滤掉已经被触发过懒加载的图片 - .filter((e) => !triggedImgList.has(e)) - // 根据位置从小到大排序 - .sort((a, b) => a.offsetTop - b.offsetTop); - - /** 上次触发的图片 */ - let lastTriggedImg: HTMLImageElement | undefined; - targetImgList.forEach((e) => { - triggedImgList.add(e); - - // 过滤掉位置相近,在触发上一张图片时已经顺带被触发了的 - if (e.offsetTop >= (lastTriggedImg?.offsetTop ?? 0) + window.innerHeight) - return; - - // 通过瞬间滚动到图片位置、触发滚动事件、再瞬间滚回来,来触发图片的懒加载 - const nowScroll = window.scrollY; - window.scroll({ top: e.offsetTop, behavior: 'auto' }); - e.dispatchEvent(new Event('scroll', { bubbles: true })); - window.scroll({ top: nowScroll, behavior: 'auto' }); - - lastTriggedImg = e; - }); - }; - - /** - * 检查搜索页面上符合标准的图片 - * - * @returns 返回是否成功找到图片 - */ - const checkFindImg = () => { - triggerLazyLoad(); - - const newImgList = [...document.getElementsByTagName('img')] - .filter((e) => e.naturalHeight > 500 && e.naturalWidth > 500) - .map((e) => e.src); - - if (newImgList.length === 0) { - if (!options.autoShow) { - clearInterval(running); - toast?.('没有找到图片', { type: 'warning' }); - } - return false; - } - - // 在发现新图片后重新渲染 - if (!isEqualArray(imgList, newImgList)) { - imgList = newImgList; - setManga({ imgList }); - setFab({ progress: 1 }); - } - - return true; - }; - - await GM.registerMenuCommand('进入漫画阅读模式', async () => { - await init(); - - if (!running) running = window.setInterval(checkFindImg, 2000); - if (!checkFindImg()) return; - setManga({ show: true }); - - // 自动启用自动加载功能 - await setOptions({ ...options, autoShow: true }); - }); - - if (isRecorded) { - await init(); - // 为了保证兼容,只能简单粗暴的不断检查网页的图片来更新数据 - running = window.setInterval(checkFindImg, 2000); - - await GM.registerMenuCommand('停止在此站点自动运行脚本', async () => { - await GM.deleteValue(window.location.hostname); - }); - } -}); diff --git a/packages/userscript/src/site/test.tsx b/packages/userscript/src/site/test.tsx deleted file mode 100644 index d6a7099a..00000000 --- a/packages/userscript/src/site/test.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import { useFab } from '../helper'; - -(async () => { - unsafeWindow.setFab = await useFab({ - tip: '阅读模式', - }); - unsafeWindow.setFab(); -})(); diff --git a/packages/userscript/src/site/yamibo.tsx b/packages/userscript/src/site/yamibo.tsx deleted file mode 100644 index 645e509b..00000000 --- a/packages/userscript/src/site/yamibo.tsx +++ /dev/null @@ -1,383 +0,0 @@ -import MdSettings from '@material-design-icons/svg/round/settings.svg'; - -import { - insertNode, - querySelector, - querySelectorAll, - scrollIntoView, - useCache, - request, - useInit, -} from '../helper'; - -declare const fid: number; - -interface History { - tid: string; - lastPageNum: number; - lastReplies: number; - lastAnchor: string; -} - -/** 签到按钮的选择器 */ -const checkInDomSelectors = - '.header-tool > li > a[href^="plugin.php?id=study_daily_attendance"]'; - -(async () => { - const { options, setFab, setManga, init } = await useInit('yamibo', { - 记录阅读进度: true, - 关闭快捷导航按钮的跳转: true, - 修正点击页数时的跳转判定: true, - 固定导航条: true, - 自动签到: true, - }); - - await GM.addStyle( - `#fab { --fab: #6E2B19; --fab_hover: #A15640; }; - - ${ - options.固定导航条 ? '.header-stackup { position: fixed !important }' : '' - } - - .historyTag { - white-space: nowrap; - - border: 2px solid #6e2b19; - } - - a.historyTag { - font-weight: bold; - - margin-left: 1em; - padding: 1px 4px; - - color: #6e2b19; - border-radius: 4px 0 0 4px; - } - a.historyTag:last-child { - border-radius: 4px; - } - - div.historyTag { - display: initial; - - margin-left: -.4em; - padding: 1px; - - color: RGB(255, 237, 187); - border-radius: 0 4px 4px 0; - background-color: #6e2b19; - } - - #threadlisttableid tbody:nth-child(2n) div.historyTag { - color: RGB(255, 246, 215); - } - - /* 隐藏签到按钮 */ - ${checkInDomSelectors} { - display: none; - } - - /* 将「回复/查看」列加宽一点 */ - .tl .num { - width: 80px !important; - } - `, - ); - - // 自动签到 - if (options.自动签到) { - const checkInDom = querySelector(checkInDomSelectors); - // eslint-disable-next-line @typescript-eslint/no-floating-promises - if (checkInDom) fetch(checkInDom.href); - } - - if (options.关闭快捷导航按钮的跳转) - // eslint-disable-next-line no-script-url - querySelector('#qmenu a')?.setAttribute('href', 'javascript:;'); - - // 增加菜单项,以便在其他板块用于调整其他功能的开关 - await GM.registerMenuCommand('显示设置菜单', () => - setFab({ - show: true, - focus: true, - tip: '设置', - children: , - onBackdropClick: () => setFab({ show: false, focus: false }), - }), - ); - - // 判断当前页是帖子 - if (/thread(-\d+){3}|mod=viewthread/.test(document.URL)) { - // 修复微博图床的链接 - querySelectorAll('img[file*="sinaimg.cn"]').forEach((e) => { - e.setAttribute('referrerpolicy', 'no-referrer'); - }); - - if ( - // 限定板块启用 - (fid === 30 || fid === 37) && - // 只在第一页生效 - !querySelector('.pg > .prev') - ) { - let imgList = querySelectorAll('.t_fsz img'); - - const updateImgList = () => { - let i = imgList.length; - while (i--) { - const img = imgList[i]; - - const file = img.getAttribute('file'); - if (file && img.src !== file) { - img.setAttribute('src', file); - img.setAttribute('lazyloaded', 'true'); - } - - // 测试例子:https://bbs.yamibo.com/thread-502399-1-1.html - - // 删掉表情和小图 - if ( - img.src.includes('static/image') || - (img.complete && - img.naturalHeight && - img.naturalWidth && - img.naturalHeight < 500 && - img.naturalWidth < 500) - ) - imgList.splice(i, 1); - } - return imgList.map((img) => img.src); - }; - - setManga({ - // 在图片加载完成后再检查一遍有没有小图,有就删掉 - onLoading: (img) => { - // 跳过符合标准的 - if (img.height && img.width && img.height > 500 && img.width > 500) - return; - - const delImgIndex = imgList.findIndex( - (image) => image.src === img.src, - ); - if (delImgIndex !== -1) imgList.splice(delImgIndex, 1); - - setManga({ imgList: imgList.map((image) => image.src) }); - }, - onExit: (isEnd) => { - if (isEnd) - scrollIntoView('.psth, .rate, #postlist > div:nth-of-type(2)'); - - setManga({ show: false }); - }, - }); - - updateImgList(); - const showComic = init(() => imgList.map((img) => img.src)); - - setFab({ progress: 1, tip: '阅读模式' }); - - // 虽然有 Fab 了不需要这个按钮,但都点习惯了没有还挺别扭的( - insertNode( - querySelector('div.pti > div.authi')!, - '|漫画阅读', - ); - document - .getElementById('comicReadMode') - ?.addEventListener('click', showComic); - - // 如果帖子内有设置目录 - if (querySelector('#threadindex')) { - querySelectorAll('#threadindex li').forEach((dom) => { - dom.addEventListener('click', () => { - setTimeout(() => { - imgList = querySelectorAll('.t_fsz img'); - setManga({ - imgList: updateImgList(), - show: options.autoShow ?? undefined, - }); - }, 1000); - }); - }); - } - - const tagDom = querySelector('.ptg.mbm.mtn > a'); - // 通过标签确定上/下一话 - if (tagDom) { - const tagId = tagDom.href.split('id=')[1]; - const reg = /(?<=\s - 回第${data.lastPageNum}页 - - ${ - lastReplies > 0 - ? `
    +${lastReplies}
    ` - : '' - } - `, - ); - }), - ); - }; - // eslint-disable-next-line @typescript-eslint/no-floating-promises - updateHistoryTag(); - - // 切换回当前页时更新提示 - document.addEventListener('visibilitychange', updateHistoryTag); - // 点击下一页后更新提示 - querySelector('#autopbn')!.addEventListener('click', updateHistoryTag); - } - } -})(); diff --git a/packages/userscript/src/types/index.d.ts b/packages/userscript/src/types/index.d.ts deleted file mode 100644 index 7ad450a6..00000000 --- a/packages/userscript/src/types/index.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -declare module '*.css'; - -declare module 'rollup-plugin-watch-assets'; - -declare const DEV_PORT: number; -declare const isDevMode: boolean; - -declare module '*.svg' { - // import type { Component, ComponentProps } from 'solid-js'; - - // const c: Component>; - // export default c; - - const src: string; - export default src; -} diff --git a/packages/userscript/tsconfig.json b/packages/userscript/tsconfig.json deleted file mode 100644 index f5944157..00000000 --- a/packages/userscript/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "include": [ - "src", - "rollup.config.ts" - ] -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e3902f6a..6d7b3419 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3,79 +3,179 @@ lockfileVersion: '6.0' importers: .: + dependencies: + '@material-design-icons/svg': + specifier: ^0.14.6 + version: 0.14.6 + fflate: + specifier: ^0.7.4 + version: 0.7.4 + panzoom: + specifier: ^9.4.3 + version: 9.4.3 + solid-element: + specifier: ^1.7.0 + version: 1.7.0(solid-js@1.7.3) + solid-js: + specifier: ^1.7.3 + version: 1.7.3 + solid-toast: + specifier: ^0.5.0 + version: 0.5.0(solid-js@1.7.3) + throttle-debounce: + specifier: ^5.0.0 + version: 5.0.0 devDependencies: + '@babel/core': + specifier: ^7.21.4 + version: 7.21.4 + '@babel/plugin-transform-runtime': + specifier: ^7.21.4 + version: 7.21.4(@babel/core@7.21.4) + '@babel/preset-env': + specifier: ^7.21.4 + version: 7.21.4(@babel/core@7.21.4) + '@babel/preset-typescript': + specifier: ^7.21.4 + version: 7.21.4(@babel/core@7.21.4) + '@babel/runtime': + specifier: ^7.17.9 + version: 7.21.0 '@release-it/conventional-changelog': specifier: ^5.1.1 - version: 5.1.1(release-it@15.8.0) + version: 5.1.1(release-it@15.10.1) + '@rollup/plugin-babel': + specifier: ^6.0.3 + version: 6.0.3(@babel/core@7.21.4)(rollup@3.20.6) + '@rollup/plugin-commonjs': + specifier: ^24.1.0 + version: 24.1.0(rollup@3.20.6) + '@rollup/plugin-node-resolve': + specifier: ^15.0.2 + version: 15.0.2(rollup@3.20.6) + '@rollup/plugin-replace': + specifier: ^5.0.2 + version: 5.0.2(rollup@3.20.6) + '@solidjs/router': + specifier: ^0.8.2 + version: 0.8.2(solid-js@1.7.3) + '@types/shelljs': + specifier: ^0.8.12 + version: 0.8.12 + '@types/throttle-debounce': + specifier: ^5.0.0 + version: 5.0.0 '@typescript-eslint/eslint-plugin': - specifier: ^5.58.0 - version: 5.58.0(@typescript-eslint/parser@5.58.0)(eslint@8.38.0)(typescript@5.0.4) + specifier: ^5.59.0 + version: 5.59.0(@typescript-eslint/parser@5.59.0)(eslint@8.38.0)(typescript@4.9.5) '@typescript-eslint/parser': - specifier: ^5.58.0 - version: 5.58.0(eslint@8.38.0)(typescript@5.0.4) + specifier: ^5.59.0 + version: 5.59.0(eslint@8.38.0)(typescript@4.9.5) + autoprefixer: + specifier: ^10.4.14 + version: 10.4.14(postcss@8.4.23) + babel-preset-solid: + specifier: ^1.7.3 + version: 1.7.3(@babel/core@7.21.4) + cssnano: + specifier: ^6.0.0 + version: 6.0.0(postcss@8.4.23) eslint: specifier: ^8.38.0 version: 8.38.0 + eslint-config-airbnb-base: + specifier: ^15.0.0 + version: 15.0.0(eslint-plugin-import@2.27.5)(eslint@8.38.0) eslint-config-prettier: specifier: ^8.8.0 version: 8.8.0(eslint@8.38.0) eslint-plugin-import: specifier: ^2.27.5 - version: 2.27.5(@typescript-eslint/parser@5.58.0)(eslint@8.38.0) + version: 2.27.5(@typescript-eslint/parser@5.59.0)(eslint@8.38.0) eslint-plugin-jsdoc: - specifier: ^41.1.1 - version: 41.1.1(eslint@8.38.0) - eslint-plugin-jsx-a11y: - specifier: ^6.7.1 - version: 6.7.1(eslint@8.38.0) + specifier: ^43.0.6 + version: 43.0.6(eslint@8.38.0) eslint-plugin-prettier: specifier: ^4.2.1 version: 4.2.1(eslint-config-prettier@8.8.0)(eslint@8.38.0)(prettier@2.8.7) + eslint-plugin-solid: + specifier: ^0.12.1 + version: 0.12.1(eslint@8.38.0)(typescript@4.9.5) fake-indexeddb: specifier: ^4.0.1 version: 4.0.1 + jsdom: + specifier: ^21.1.1 + version: 21.1.1 + normalize.css: + specifier: ^8.0.1 + version: 8.0.1 + postcss-import: + specifier: ^15.1.0 + version: 15.1.0(postcss@8.4.23) + postcss-nesting: + specifier: ^11.2.2 + version: 11.2.2(postcss@8.4.23) prettier: specifier: ^2.8.7 version: 2.8.7 release-it: - specifier: ^15.8.0 - version: 15.8.0 - rollup-plugin-userscript-metablock: - specifier: ^0.3.1 - version: 0.3.1 + specifier: ^15.10.1 + version: 15.10.1 + rollup: + specifier: ^3.20.6 + version: 3.20.6 + rollup-plugin-styles: + specifier: ^4.0.0 + version: 4.0.0(rollup@3.20.6) + rollup-plugin-ts: + specifier: ^3.2.0 + version: 3.2.0(@babel/core@7.21.4)(@babel/plugin-transform-runtime@7.21.4)(@babel/preset-env@7.21.4)(@babel/preset-typescript@7.21.4)(@babel/runtime@7.21.0)(rollup@3.20.6)(typescript@4.9.5) + rollup-plugin-watch-external: + specifier: ^1.0.2 + version: 1.0.2(rollup@3.20.6) shelljs: specifier: ^0.8.5 version: 0.8.5 stylelint: - specifier: ^14.11.0 - version: 14.13.0 + specifier: ^15.6.0 + version: 15.6.0 stylelint-config-clean-order: - specifier: ^0.9.0 - version: 0.9.0(stylelint@14.13.0) + specifier: ^5.0.1 + version: 5.0.1(stylelint@15.6.0) stylelint-config-prettier: - specifier: ^9.0.3 - version: 9.0.3(stylelint@14.13.0) + specifier: ^9.0.5 + version: 9.0.5(stylelint@15.6.0) stylelint-config-recess-order: - specifier: ^3.0.0 - version: 3.0.0(stylelint@14.13.0) + specifier: ^4.0.0 + version: 4.0.0(stylelint@15.6.0) stylelint-config-standard: - specifier: ^28.0.0 - version: 28.0.0(stylelint@14.13.0) + specifier: ^33.0.0 + version: 33.0.0(stylelint@15.6.0) stylelint-high-performance-animation: - specifier: ^1.6.0 - version: 1.6.0(stylelint@14.13.0) + specifier: ^1.8.0 + version: 1.8.0(stylelint@15.6.0) stylelint-order: - specifier: ^5.0.0 - version: 5.0.0(stylelint@14.13.0) + specifier: ^6.0.3 + version: 6.0.3(stylelint@15.6.0) stylelint-prettier: - specifier: ^2.0.0 - version: 2.0.0(prettier@2.8.7)(stylelint@14.13.0) - typescript: - specifier: ^5.0.4 - version: 5.0.4 + specifier: ^3.0.0 + version: 3.0.0(prettier@2.8.7)(stylelint@15.6.0) + svgo: + specifier: ^3.0.2 + version: 3.0.2 + tslib: + specifier: ^2.5.0 + version: 2.5.0 + vite: + specifier: ^4.2.2 + version: 4.2.2(@types/node@18.15.11) + vite-plugin-solid: + specifier: ^2.7.0 + version: 2.7.0(solid-js@1.7.3)(vite@4.2.2) vitest: - specifier: ^0.28.4 - version: 0.28.4 + specifier: ^0.30.1 + version: 0.30.1(jsdom@21.1.1) packages/ui-component: dependencies: @@ -1665,35 +1765,60 @@ packages: to-fast-properties: 2.0.0 dev: true - /@csstools/selector-specificity@2.0.2(postcss-selector-parser@6.0.10)(postcss@8.4.17): + /@csstools/css-parser-algorithms@2.1.1(@csstools/css-tokenizer@2.1.1): + resolution: {integrity: sha512-viRnRh02AgO4mwIQb2xQNJju0i+Fh9roNgmbR5xEuG7J3TGgxjnE95HnBLgsFJOJOksvcfxOUCgODcft6Y07cA==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + '@csstools/css-tokenizer': ^2.1.1 + dependencies: + '@csstools/css-tokenizer': 2.1.1 + dev: true + + /@csstools/css-tokenizer@2.1.1: + resolution: {integrity: sha512-GbrTj2Z8MCTUv+52GE0RbFGM527xuXZ0Xa5g0Z+YN573uveS4G0qi6WNOMyz3yrFM/jaILTTwJ0+umx81EzqfA==} + engines: {node: ^14 || ^16 || >=18} + dev: true + + /@csstools/media-query-list-parser@2.0.4(@csstools/css-parser-algorithms@2.1.1)(@csstools/css-tokenizer@2.1.1): + resolution: {integrity: sha512-GyYot6jHgcSDZZ+tLSnrzkR7aJhF2ZW6d+CXH66mjy5WpAQhZD4HDke2OQ36SivGRWlZJpAz7TzbW6OKlEpxAA==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + '@csstools/css-parser-algorithms': ^2.1.1 + '@csstools/css-tokenizer': ^2.1.1 + dependencies: + '@csstools/css-parser-algorithms': 2.1.1(@csstools/css-tokenizer@2.1.1) + '@csstools/css-tokenizer': 2.1.1 + dev: true + + /@csstools/selector-specificity@2.0.2(postcss-selector-parser@6.0.10)(postcss@8.4.21): resolution: {integrity: sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==} engines: {node: ^12 || ^14 || >=16} peerDependencies: postcss: ^8.2 postcss-selector-parser: ^6.0.10 dependencies: - postcss: 8.4.17 + postcss: 8.4.21 postcss-selector-parser: 6.0.10 dev: true - /@csstools/selector-specificity@2.0.2(postcss-selector-parser@6.0.10)(postcss@8.4.21): + /@csstools/selector-specificity@2.0.2(postcss-selector-parser@6.0.10)(postcss@8.4.23): resolution: {integrity: sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==} engines: {node: ^12 || ^14 || >=16} peerDependencies: postcss: ^8.2 postcss-selector-parser: ^6.0.10 dependencies: - postcss: 8.4.21 + postcss: 8.4.23 postcss-selector-parser: 6.0.10 dev: true - /@es-joy/jsdoccomment@0.37.0: - resolution: {integrity: sha512-hjK0wnsPCYLlF+HHB4R/RbUjOWeLW2SlarB67+Do5WsKILOkmIZvvPJFbtWSmbypxcjpoECLAMzoao0D4Bg5ZQ==} - engines: {node: ^14 || ^16 || ^17 || ^18 || ^19} + /@csstools/selector-specificity@2.2.0(postcss-selector-parser@6.0.11): + resolution: {integrity: sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + postcss-selector-parser: ^6.0.10 dependencies: - comment-parser: 1.3.1 - esquery: 1.5.0 - jsdoc-type-pratt-parser: 4.0.0 + postcss-selector-parser: 6.0.11 dev: true /@es-joy/jsdoccomment@0.37.1: @@ -2061,7 +2186,7 @@ packages: resolution: {integrity: sha512-/aFM2M4HVDBT/jjDBa84sJniv1t9Gm/rLkalaz9htOm+L+8JMj1k9w0CkUdcxNyNxZPlTxKPVko+m1VlM58ZVA==} engines: {node: '>= 14'} dependencies: - '@octokit/types': 9.0.0 + '@octokit/types': 9.1.4 dev: true /@octokit/core@4.2.0: @@ -2072,7 +2197,7 @@ packages: '@octokit/graphql': 5.0.5 '@octokit/request': 6.2.3 '@octokit/request-error': 3.0.3 - '@octokit/types': 9.0.0 + '@octokit/types': 9.1.4 before-after-hook: 2.2.3 universal-user-agent: 6.0.0 transitivePeerDependencies: @@ -2083,7 +2208,7 @@ packages: resolution: {integrity: sha512-LG4o4HMY1Xoaec87IqQ41TQ+glvIeTKqfjkCEmt5AIwDZJwQeVZFIEYXrYY6yLwK+pAScb9Gj4q+Nz2qSw1roA==} engines: {node: '>= 14'} dependencies: - '@octokit/types': 9.0.0 + '@octokit/types': 9.1.4 is-plain-object: 5.0.0 universal-user-agent: 6.0.0 dev: true @@ -2093,14 +2218,14 @@ packages: engines: {node: '>= 14'} dependencies: '@octokit/request': 6.2.3 - '@octokit/types': 9.0.0 + '@octokit/types': 9.1.4 universal-user-agent: 6.0.0 transitivePeerDependencies: - encoding dev: true - /@octokit/openapi-types@16.0.0: - resolution: {integrity: sha512-JbFWOqTJVLHZSUUoF4FzAZKYtqdxWu9Z5m2QQnOyEa04fOFljvyh7D3GYKbfuaSWisqehImiVIMG4eyJeP5VEA==} + /@octokit/openapi-types@17.0.0: + resolution: {integrity: sha512-V8BVJGN0ZmMlURF55VFHFd/L92XQQ43KvFjNmY1IYbCN3V/h/uUFV6iQi19WEHM395Nn+1qhUbViCAD/1czzog==} dev: true /@octokit/plugin-paginate-rest@6.0.0(@octokit/core@4.2.0): @@ -2110,7 +2235,7 @@ packages: '@octokit/core': '>=4' dependencies: '@octokit/core': 4.2.0 - '@octokit/types': 9.0.0 + '@octokit/types': 9.1.4 dev: true /@octokit/plugin-request-log@1.0.4(@octokit/core@4.2.0): @@ -2128,7 +2253,7 @@ packages: '@octokit/core': '>=3' dependencies: '@octokit/core': 4.2.0 - '@octokit/types': 9.0.0 + '@octokit/types': 9.1.4 deprecation: 2.3.1 dev: true @@ -2136,7 +2261,7 @@ packages: resolution: {integrity: sha512-crqw3V5Iy2uOU5Np+8M/YexTlT8zxCfI+qu+LxUB7SZpje4Qmx3mub5DfEKSO8Ylyk0aogi6TYdf6kxzh2BguQ==} engines: {node: '>= 14'} dependencies: - '@octokit/types': 9.0.0 + '@octokit/types': 9.1.4 deprecation: 2.3.1 once: 1.4.0 dev: true @@ -2147,7 +2272,7 @@ packages: dependencies: '@octokit/endpoint': 7.0.5 '@octokit/request-error': 3.0.3 - '@octokit/types': 9.0.0 + '@octokit/types': 9.1.4 is-plain-object: 5.0.0 node-fetch: 2.6.9 universal-user-agent: 6.0.0 @@ -2167,14 +2292,14 @@ packages: - encoding dev: true - /@octokit/types@9.0.0: - resolution: {integrity: sha512-LUewfj94xCMH2rbD5YJ+6AQ4AVjFYTgpp6rboWM5T7N3IsIF65SBEOVcYMGAEzO/kKNiNaW4LoWtoThOhH06gw==} + /@octokit/types@9.1.4: + resolution: {integrity: sha512-5d9vYHzC/yG9eyYBO2Pis4BM4tQfFcyFUWBquDgCzcmFG+sgBiRQ2JCY55HG/hdxvESt9IZUoRtzOm66Qv/GWw==} dependencies: - '@octokit/openapi-types': 16.0.0 + '@octokit/openapi-types': 17.0.0 dev: true - /@pnpm/config.env-replace@1.0.0: - resolution: {integrity: sha512-ZVPVDi1E8oeXlYqkGRtX0CkzLTwE2zt62bjWaWKaAvI8NZqHzlMvGeSNDpW+JB3+aKanYb4UETJOF1/CxGPemA==} + /@pnpm/config.env-replace@1.1.0: + resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} engines: {node: '>=12.22.0'} dev: true @@ -2185,16 +2310,16 @@ packages: graceful-fs: 4.2.10 dev: true - /@pnpm/npm-conf@2.1.0: - resolution: {integrity: sha512-Oe6ntvgsMTE3hDIqy6sajqHF+MnzJrOF06qC2QSiUEybLL7cp6tjoKUa32gpd9+KPVl4QyMs3E3nsXrx/Vdnlw==} + /@pnpm/npm-conf@2.1.1: + resolution: {integrity: sha512-yfRcuupmxxeDOSxvw4g+wFCrGiPD0L32f5WMzqMXp7Rl93EOCdFiDcaSNnZ10Up9GdNqkj70UTa8hfhPFphaZA==} engines: {node: '>=12'} dependencies: - '@pnpm/config.env-replace': 1.0.0 + '@pnpm/config.env-replace': 1.1.0 '@pnpm/network.ca-file': 1.0.2 config-chain: 1.1.13 dev: true - /@release-it/conventional-changelog@5.1.1(release-it@15.8.0): + /@release-it/conventional-changelog@5.1.1(release-it@15.10.1): resolution: {integrity: sha512-QtbDBe36dQfzexAfDYrbLPvd5Cb5bMWmLcjcGhCOWBss7fe1/gCjoxDULVz+7N7G5Nu2UMeBwHcUp/w8RDh5VQ==} engines: {node: '>=14'} peerDependencies: @@ -2203,7 +2328,7 @@ packages: concat-stream: 2.0.0 conventional-changelog: 3.1.25 conventional-recommended-bump: 6.1.0 - release-it: 15.8.0 + release-it: 15.10.1 semver: 7.3.8 dev: true @@ -2600,6 +2725,11 @@ packages: engines: {node: '>= 6'} dev: true + /@tootallnate/once@2.0.0: + resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} + engines: {node: '>= 10'} + dev: true + /@trysound/sax@0.2.0: resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} @@ -2712,14 +2842,17 @@ packages: resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} dev: true - /@types/semver@7.3.12: - resolution: {integrity: sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A==} - dev: true - /@types/semver@7.3.13: resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==} dev: true + /@types/shelljs@0.8.12: + resolution: {integrity: sha512-ZA8U81/gldY+rR5zl/7HSHrG2KDfEb3lzG6uCUDhW1DTQE9yC/VBQ45fXnXq8f3CgInfhZmjtdu/WOUlrXRQUg==} + dependencies: + '@types/glob': 7.2.0 + '@types/node': 18.15.11 + dev: true + /@types/throttle-debounce@5.0.0: resolution: {integrity: sha512-Pb7k35iCGFcGPECoNE4DYp3Oyf2xcTd3FbFQxXUI9hEYKUl6YX+KLf7HrBmgVcD05nl50LIH6i+80js4iYmWbw==} dev: true @@ -2728,34 +2861,6 @@ packages: resolution: {integrity: sha512-N1rW+njavs70y2cApeIw1vLMYXRwfBy+7trgavGuuTfOd7j1Yh7QTRc/yqsPl6ncokt72ZXuxEU0PiCp9bSwNQ==} dev: true - /@typescript-eslint/eslint-plugin@5.58.0(@typescript-eslint/parser@5.58.0)(eslint@8.38.0)(typescript@5.0.4): - resolution: {integrity: sha512-vxHvLhH0qgBd3/tW6/VccptSfc8FxPQIkmNTVLWcCOVqSBvqpnKkBTYrhcGlXfSnd78azwe+PsjYFj0X34/njA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - '@typescript-eslint/parser': ^5.0.0 - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@eslint-community/regexpp': 4.5.0 - '@typescript-eslint/parser': 5.58.0(eslint@8.38.0)(typescript@5.0.4) - '@typescript-eslint/scope-manager': 5.58.0 - '@typescript-eslint/type-utils': 5.58.0(eslint@8.38.0)(typescript@5.0.4) - '@typescript-eslint/utils': 5.58.0(eslint@8.38.0)(typescript@5.0.4) - debug: 4.3.4 - eslint: 8.38.0 - grapheme-splitter: 1.0.4 - ignore: 5.2.0 - natural-compare-lite: 1.4.0 - semver: 7.3.8 - tsutils: 3.21.0(typescript@5.0.4) - typescript: 5.0.4 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/eslint-plugin@5.59.0(@typescript-eslint/parser@5.59.0)(eslint@8.38.0)(typescript@4.9.5): resolution: {integrity: sha512-p0QgrEyrxAWBecR56gyn3wkG15TJdI//eetInP3zYRewDh0XS+DhB3VUAd3QqvziFsfaQIoIuZMxZRB7vXYaYw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2784,26 +2889,6 @@ packages: - supports-color dev: true - /@typescript-eslint/parser@5.58.0(eslint@8.38.0)(typescript@5.0.4): - resolution: {integrity: sha512-ixaM3gRtlfrKzP8N6lRhBbjTow1t6ztfBvQNGuRM8qH1bjFFXIJ35XY+FC0RRBKn3C6cT+7VW1y8tNm7DwPHDQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/scope-manager': 5.58.0 - '@typescript-eslint/types': 5.58.0 - '@typescript-eslint/typescript-estree': 5.58.0(typescript@5.0.4) - debug: 4.3.4 - eslint: 8.38.0 - typescript: 5.0.4 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/parser@5.59.0(eslint@8.38.0)(typescript@4.9.5): resolution: {integrity: sha512-qK9TZ70eJtjojSUMrrEwA9ZDQ4N0e/AuoOIgXuNBorXYcBDk397D2r5MIe1B3cok/oCtdNC5j+lUUpVB+Dpb+w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2824,14 +2909,6 @@ packages: - supports-color dev: true - /@typescript-eslint/scope-manager@5.58.0: - resolution: {integrity: sha512-b+w8ypN5CFvrXWQb9Ow9T4/6LC2MikNf1viLkYTiTbkQl46CnR69w7lajz1icW0TBsYmlpg+mRzFJ4LEJ8X9NA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - '@typescript-eslint/types': 5.58.0 - '@typescript-eslint/visitor-keys': 5.58.0 - dev: true - /@typescript-eslint/scope-manager@5.59.0: resolution: {integrity: sha512-tsoldKaMh7izN6BvkK6zRMINj4Z2d6gGhO2UsI8zGZY3XhLq1DndP3Ycjhi1JwdwPRwtLMW4EFPgpuKhbCGOvQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2840,26 +2917,6 @@ packages: '@typescript-eslint/visitor-keys': 5.59.0 dev: true - /@typescript-eslint/type-utils@5.58.0(eslint@8.38.0)(typescript@5.0.4): - resolution: {integrity: sha512-FF5vP/SKAFJ+LmR9PENql7fQVVgGDOS+dq3j+cKl9iW/9VuZC/8CFmzIP0DLKXfWKpRHawJiG70rVH+xZZbp8w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: '*' - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/typescript-estree': 5.58.0(typescript@5.0.4) - '@typescript-eslint/utils': 5.58.0(eslint@8.38.0)(typescript@5.0.4) - debug: 4.3.4 - eslint: 8.38.0 - tsutils: 3.21.0(typescript@5.0.4) - typescript: 5.0.4 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/type-utils@5.59.0(eslint@8.38.0)(typescript@4.9.5): resolution: {integrity: sha512-d/B6VSWnZwu70kcKQSCqjcXpVH+7ABKH8P1KNn4K7j5PXXuycZTPXF44Nui0TEm6rbWGi8kc78xRgOC4n7xFgA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2880,37 +2937,11 @@ packages: - supports-color dev: true - /@typescript-eslint/types@5.58.0: - resolution: {integrity: sha512-JYV4eITHPzVQMnHZcYJXl2ZloC7thuUHrcUmxtzvItyKPvQ50kb9QXBkgNAt90OYMqwaodQh2kHutWZl1fc+1g==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - /@typescript-eslint/types@5.59.0: resolution: {integrity: sha512-yR2h1NotF23xFFYKHZs17QJnB51J/s+ud4PYU4MqdZbzeNxpgUr05+dNeCN/bb6raslHvGdd6BFCkVhpPk/ZeA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/typescript-estree@5.58.0(typescript@5.0.4): - resolution: {integrity: sha512-cRACvGTodA+UxnYM2uwA2KCwRL7VAzo45syNysqlMyNyjw0Z35Icc9ihPJZjIYuA5bXJYiJ2YGUB59BqlOZT1Q==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/types': 5.58.0 - '@typescript-eslint/visitor-keys': 5.58.0 - debug: 4.3.4 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.5.0 - tsutils: 3.21.0(typescript@5.0.4) - typescript: 5.0.4 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/typescript-estree@5.59.0(typescript@4.9.5): resolution: {integrity: sha512-sUNnktjmI8DyGzPdZ8dRwW741zopGxltGs/SAPgGL/AAgDpiLsCFLcMNSpbfXfmnNeHmK9h3wGmCkGRGAoUZAg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2932,26 +2963,6 @@ packages: - supports-color dev: true - /@typescript-eslint/utils@5.58.0(eslint@8.38.0)(typescript@5.0.4): - resolution: {integrity: sha512-gAmLOTFXMXOC+zP1fsqm3VceKSBQJNzV385Ok3+yzlavNHZoedajjS4UyS21gabJYcobuigQPs/z71A9MdJFqQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.38.0) - '@types/json-schema': 7.0.11 - '@types/semver': 7.3.12 - '@typescript-eslint/scope-manager': 5.58.0 - '@typescript-eslint/types': 5.58.0 - '@typescript-eslint/typescript-estree': 5.58.0(typescript@5.0.4) - eslint: 8.38.0 - eslint-scope: 5.1.1 - semver: 7.5.0 - transitivePeerDependencies: - - supports-color - - typescript - dev: true - /@typescript-eslint/utils@5.59.0(eslint@8.38.0)(typescript@4.9.5): resolution: {integrity: sha512-GGLFd+86drlHSvPgN/el6dRQNYYGOvRSDVydsUaQluwIW3HvbXuxyuD5JETvBt/9qGYe+lOrDk6gRrWOHb/FvA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2972,14 +2983,6 @@ packages: - typescript dev: true - /@typescript-eslint/visitor-keys@5.58.0: - resolution: {integrity: sha512-/fBraTlPj0jwdyTwLyrRTxv/3lnU2H96pNTVM6z3esTWLtA5MZ9ghSMJ7Rb+TtUAdtEw9EyJzJ0EydIMKxQ9gA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - '@typescript-eslint/types': 5.58.0 - eslint-visitor-keys: 3.4.0 - dev: true - /@typescript-eslint/visitor-keys@5.59.0: resolution: {integrity: sha512-qZ3iXxQhanchCeaExlKPV3gDQFxMUmU35xfd5eCXB6+kUw1TUAbIy2n7QIrwz9s98DQLzNWyHp61fY0da4ZcbA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2988,35 +2991,42 @@ packages: eslint-visitor-keys: 3.4.0 dev: true - /@vitest/expect@0.28.4: - resolution: {integrity: sha512-JqK0NZ4brjvOSL8hXAnIsfi+jxDF7rH/ZWCGCt0FAqRnVFc1hXsfwXksQvEnKqD84avRt3gmeXoK4tNbmkoVsQ==} + /@vitest/expect@0.30.1: + resolution: {integrity: sha512-c3kbEtN8XXJSeN81iDGq29bUzSjQhjES2WR3aColsS4lPGbivwLtas4DNUe0jD9gg/FYGIteqOenfU95EFituw==} dependencies: - '@vitest/spy': 0.28.4 - '@vitest/utils': 0.28.4 + '@vitest/spy': 0.30.1 + '@vitest/utils': 0.30.1 chai: 4.3.7 dev: true - /@vitest/runner@0.28.4: - resolution: {integrity: sha512-Q8UV6GjDvBSTfUoq0QXVCNpNOUrWu4P2qvRq7ssJWzn0+S0ojbVOxEjMt+8a32X6SdkhF8ak+2nkppsqV0JyNQ==} + /@vitest/runner@0.30.1: + resolution: {integrity: sha512-W62kT/8i0TF1UBCNMRtRMOBWJKRnNyv9RrjIgdUryEe0wNpGZvvwPDLuzYdxvgSckzjp54DSpv1xUbv4BQ0qVA==} dependencies: - '@vitest/utils': 0.28.4 + '@vitest/utils': 0.30.1 + concordance: 5.0.4 p-limit: 4.0.0 pathe: 1.1.0 dev: true - /@vitest/spy@0.28.4: - resolution: {integrity: sha512-8WuhfXLlvCXpNXEGJW6Gc+IKWI32435fQJLh43u70HnZ1otJOa2Cmg2Wy2Aym47ZnNCP4NolF+8cUPwd0MigKQ==} + /@vitest/snapshot@0.30.1: + resolution: {integrity: sha512-fJZqKrE99zo27uoZA/azgWyWbFvM1rw2APS05yB0JaLwUIg9aUtvvnBf4q7JWhEcAHmSwbrxKFgyBUga6tq9Tw==} dependencies: - tinyspy: 1.1.1 + magic-string: 0.30.0 + pathe: 1.1.0 + pretty-format: 27.5.1 dev: true - /@vitest/utils@0.28.4: - resolution: {integrity: sha512-l2QztOLdc2LkR+w/lP52RGh8hW+Ul4KESmCAgVE8q737I7e7bQoAfkARKpkPJ4JQtGpwW4deqlj1732VZD7TFw==} + /@vitest/spy@0.30.1: + resolution: {integrity: sha512-YfJeIf37GvTZe04ZKxzJfnNNuNSmTEGnla2OdL60C8od16f3zOfv9q9K0nNii0NfjDJRt/CVN/POuY5/zTS+BA==} dependencies: - cli-truncate: 3.1.0 - diff: 5.1.0 + tinyspy: 2.1.0 + dev: true + + /@vitest/utils@0.30.1: + resolution: {integrity: sha512-/c8Xv2zUVc+rnNt84QF0Y0zkfxnaGhp87K2dYJMLtLOIckPzuxLVzAtFCicGFdB4NeBHNzTRr1tNn7rCtQcWFA==} + dependencies: + concordance: 5.0.4 loupe: 2.3.6 - picocolors: 1.0.0 pretty-format: 27.5.1 dev: true @@ -3033,6 +3043,17 @@ packages: through: 2.3.8 dev: true + /abab@2.0.6: + resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} + dev: true + + /acorn-globals@7.0.1: + resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==} + dependencies: + acorn: 8.8.2 + acorn-walk: 8.2.0 + dev: true + /acorn-jsx@5.3.2(acorn@8.8.2): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -3082,8 +3103,8 @@ packages: uri-js: 4.4.1 dev: true - /ajv@8.11.0: - resolution: {integrity: sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==} + /ajv@8.12.0: + resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} dependencies: fast-deep-equal: 3.1.3 json-schema-traverse: 1.0.0 @@ -3108,11 +3129,11 @@ packages: engines: {node: '>=6'} dev: true - /ansi-escapes@6.0.0: - resolution: {integrity: sha512-IG23inYII3dWlU2EyiAiGj6Bwal5GzsgPMwjYGvc1HPE2dgbj4ZB5ToWBKSquKw74nB3TIuOwaI6/jSULzfgrw==} + /ansi-escapes@6.2.0: + resolution: {integrity: sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==} engines: {node: '>=14.16'} dependencies: - type-fest: 3.6.1 + type-fest: 3.9.0 dev: true /ansi-regex@5.0.1: @@ -3246,6 +3267,10 @@ packages: retry: 0.13.1 dev: true + /asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + dev: true + /autoprefixer@10.4.14(postcss@8.4.21): resolution: {integrity: sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==} engines: {node: ^10 || ^12 || >=14} @@ -3262,6 +3287,22 @@ packages: postcss-value-parser: 4.2.0 dev: true + /autoprefixer@10.4.14(postcss@8.4.23): + resolution: {integrity: sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + dependencies: + browserslist: 4.21.5 + caniuse-lite: 1.0.30001480 + fraction.js: 4.2.0 + normalize-range: 0.1.2 + picocolors: 1.0.0 + postcss: 8.4.23 + postcss-value-parser: 4.2.0 + dev: true + /available-typed-arrays@1.0.5: resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} engines: {node: '>= 0.4'} @@ -3375,16 +3416,25 @@ packages: resolution: {integrity: sha512-gbIqZ/eslnUFC1tjEvtz0sgx+xTK20wDnYMIA27VA04R7w6xxXQPZDbibjA9DTWZRA2CXtwHykkVzlCaAJAZig==} dev: false + /big-integer@1.6.51: + resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==} + engines: {node: '>=0.6'} + dev: true + /bl@5.1.0: resolution: {integrity: sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==} dependencies: buffer: 6.0.3 inherits: 2.0.4 - readable-stream: 3.6.0 + readable-stream: 3.6.2 + dev: true + + /blueimp-md5@2.19.0: + resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==} dev: true /boolbase@1.0.0: - resolution: {integrity: sha1-aN/1++YMUes3cl6p4+0xDcwed24=} + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} dev: true /boxen@7.0.2: @@ -3401,6 +3451,13 @@ packages: wrap-ansi: 8.1.0 dev: true + /bplist-parser@0.2.0: + resolution: {integrity: sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==} + engines: {node: '>= 5.10.0'} + dependencies: + big-integer: 1.6.51 + dev: true + /brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: @@ -3464,6 +3521,13 @@ packages: engines: {node: '>=6'} dev: true + /bundle-name@3.0.0: + resolution: {integrity: sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==} + engines: {node: '>=12'} + dependencies: + run-applescript: 5.0.0 + dev: true + /bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} @@ -3479,8 +3543,8 @@ packages: engines: {node: '>=14.16'} dev: true - /cacheable-request@10.2.8: - resolution: {integrity: sha512-IDVO5MJ4LItE6HKFQTqT2ocAQsisOoCTUDu1ddCmnhyiwFQjXNPp4081Xj23N4tO+AFEFNzGuNEf/c8Gwwt15A==} + /cacheable-request@10.2.10: + resolution: {integrity: sha512-v6WB+Epm/qO4Hdlio/sfUn69r5Shgh39SsE9DSd4bIezP0mblOlObI+I0kUEM7J0JFc+I7pSeMeYaOYtX1N/VQ==} engines: {node: '>=14.16'} dependencies: '@types/http-cache-semantics': 4.0.1 @@ -3606,19 +3670,11 @@ packages: restore-cursor: 4.0.0 dev: true - /cli-spinners@2.7.0: - resolution: {integrity: sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==} + /cli-spinners@2.8.0: + resolution: {integrity: sha512-/eG5sJcvEIwxcdYM86k5tPwn0MUzkX5YY3eImTGpJOZgVe4SdTMY14vQpcxgBzJ0wXwAYrS8E+c3uHeK4JNyzQ==} engines: {node: '>=6'} dev: true - /cli-truncate@3.1.0: - resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - slice-ansi: 5.0.0 - string-width: 5.1.2 - dev: true - /cli-width@4.0.0: resolution: {integrity: sha512-ZksGS2xpa/bYkNzN3BAw1wEjsLV/ZKOf/CCrJ/QOBsxx6fOARIkwTutxp1XIOIohi6HKmOFjMoK/XaqDVUpEEw==} engines: {node: '>= 12'} @@ -3651,7 +3707,7 @@ packages: dev: true /color-name@1.1.3: - resolution: {integrity: sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=} + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} dev: true /color-name@1.1.4: @@ -3662,6 +3718,13 @@ packages: resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} dev: true + /combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 + dev: true + /commander@7.2.0: resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} engines: {node: '>= 10'} @@ -3673,7 +3736,7 @@ packages: dev: true /commondir@1.0.1: - resolution: {integrity: sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=} + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} dev: true /compare-func@2.0.0: @@ -3707,7 +3770,7 @@ packages: dependencies: buffer-from: 1.1.2 inherits: 2.0.4 - readable-stream: 3.6.0 + readable-stream: 3.6.2 typedarray: 0.0.6 dev: true @@ -3717,6 +3780,20 @@ packages: source-map: 0.6.1 dev: true + /concordance@5.0.4: + resolution: {integrity: sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==} + engines: {node: '>=10.18.0 <11 || >=12.14.0 <13 || >=14'} + dependencies: + date-time: 3.1.0 + esutils: 2.0.3 + fast-diff: 1.2.0 + js-string-escape: 1.0.1 + lodash: 4.17.21 + md5-hex: 3.0.1 + semver: 7.5.0 + well-known-symbols: 2.0.0 + dev: true + /config-chain@1.1.13: resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} dependencies: @@ -3930,8 +4007,8 @@ packages: yaml: 1.10.2 dev: true - /cosmiconfig@8.1.0: - resolution: {integrity: sha512-0tLZ9URlPGU7JsKq0DQOQ3FoRsYX8xDZ7xMiATQfaiGMz7EHowNkbU9u1coAOmnh9p/1ySpm0RB3JNWRXM5GCg==} + /cosmiconfig@8.1.3: + resolution: {integrity: sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==} engines: {node: '>=14'} dependencies: import-fresh: 3.3.0 @@ -3980,6 +4057,15 @@ packages: postcss: 8.4.21 dev: true + /css-declaration-sorter@6.3.1(postcss@8.4.23): + resolution: {integrity: sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w==} + engines: {node: ^10 || ^12 || >=14} + peerDependencies: + postcss: ^8.0.9 + dependencies: + postcss: 8.4.23 + dev: true + /css-functions-list@3.1.0: resolution: {integrity: sha512-/9lCvYZaUbBGvYUgYGFJ4dcYiyqdhSjG7IPVluoV8A1ILjkF7ilmhp1OGUz8n+nmBcu0RNrQAzgD8B6FJbrt2w==} engines: {node: '>=12.22'} @@ -4116,6 +4202,44 @@ packages: postcss-unique-selectors: 6.0.0(postcss@8.4.21) dev: true + /cssnano-preset-default@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-BDxlaFzObRDXUiCCBQUNQcI+f1/aX2mgoNtXGjV6PG64POcHoDUoX+LgMWw+Q4609QhxwkcSnS65YFs42RA6qQ==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + css-declaration-sorter: 6.3.1(postcss@8.4.23) + cssnano-utils: 4.0.0(postcss@8.4.23) + postcss: 8.4.23 + postcss-calc: 8.2.4(postcss@8.4.23) + postcss-colormin: 6.0.0(postcss@8.4.23) + postcss-convert-values: 6.0.0(postcss@8.4.23) + postcss-discard-comments: 6.0.0(postcss@8.4.23) + postcss-discard-duplicates: 6.0.0(postcss@8.4.23) + postcss-discard-empty: 6.0.0(postcss@8.4.23) + postcss-discard-overridden: 6.0.0(postcss@8.4.23) + postcss-merge-longhand: 6.0.0(postcss@8.4.23) + postcss-merge-rules: 6.0.0(postcss@8.4.23) + postcss-minify-font-values: 6.0.0(postcss@8.4.23) + postcss-minify-gradients: 6.0.0(postcss@8.4.23) + postcss-minify-params: 6.0.0(postcss@8.4.23) + postcss-minify-selectors: 6.0.0(postcss@8.4.23) + postcss-normalize-charset: 6.0.0(postcss@8.4.23) + postcss-normalize-display-values: 6.0.0(postcss@8.4.23) + postcss-normalize-positions: 6.0.0(postcss@8.4.23) + postcss-normalize-repeat-style: 6.0.0(postcss@8.4.23) + postcss-normalize-string: 6.0.0(postcss@8.4.23) + postcss-normalize-timing-functions: 6.0.0(postcss@8.4.23) + postcss-normalize-unicode: 6.0.0(postcss@8.4.23) + postcss-normalize-url: 6.0.0(postcss@8.4.23) + postcss-normalize-whitespace: 6.0.0(postcss@8.4.23) + postcss-ordered-values: 6.0.0(postcss@8.4.23) + postcss-reduce-initial: 6.0.0(postcss@8.4.23) + postcss-reduce-transforms: 6.0.0(postcss@8.4.23) + postcss-svgo: 6.0.0(postcss@8.4.23) + postcss-unique-selectors: 6.0.0(postcss@8.4.23) + dev: true + /cssnano-utils@3.1.0(postcss@8.4.21): resolution: {integrity: sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==} engines: {node: ^10 || ^12 || >=14.0} @@ -4134,6 +4258,15 @@ packages: postcss: 8.4.21 dev: true + /cssnano-utils@4.0.0(postcss@8.4.23): + resolution: {integrity: sha512-Z39TLP+1E0KUcd7LGyF4qMfu8ZufI0rDzhdyAMsa/8UyNUU8wpS0fhdBxbQbv32r64ea00h4878gommRVg2BHw==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + postcss: 8.4.23 + dev: true + /cssnano@5.1.13(postcss@8.4.21): resolution: {integrity: sha512-S2SL2ekdEz6w6a2epXn4CmMKU4K3KpcyXLKfAYc9UQQqJRkD/2eLUG0vJ3Db/9OvO5GuAdgXw3pFbR6abqghDQ==} engines: {node: ^10 || ^12 || >=14.0} @@ -4157,6 +4290,17 @@ packages: postcss: 8.4.21 dev: true + /cssnano@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-RGlcbzGhzEBCHuQe3k+Udyj5M00z0pm9S+VurHXFEOXxH+y0sVrJH2sMzoyz2d8N1EScazg+DVvmgyx0lurwwA==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + cssnano-preset-default: 6.0.0(postcss@8.4.23) + lilconfig: 2.1.0 + postcss: 8.4.23 + dev: true + /csso@4.2.0: resolution: {integrity: sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==} engines: {node: '>=8.0.0'} @@ -4171,6 +4315,13 @@ packages: css-tree: 2.2.1 dev: true + /cssstyle@3.0.0: + resolution: {integrity: sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==} + engines: {node: '>=14'} + dependencies: + rrweb-cssom: 0.6.0 + dev: true + /csstype@3.1.1: resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==} @@ -4193,6 +4344,22 @@ packages: engines: {node: '>= 12'} dev: true + /data-urls@4.0.0: + resolution: {integrity: sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==} + engines: {node: '>=14'} + dependencies: + abab: 2.0.6 + whatwg-mimetype: 3.0.0 + whatwg-url: 12.0.1 + dev: true + + /date-time@3.1.0: + resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==} + engines: {node: '>=6'} + dependencies: + time-zone: 1.0.0 + dev: true + /dateformat@3.0.3: resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==} dev: true @@ -4220,8 +4387,8 @@ packages: ms: 2.1.2 dev: true - /decamelize-keys@1.1.0: - resolution: {integrity: sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg==} + /decamelize-keys@1.1.1: + resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} engines: {node: '>=0.10.0'} dependencies: decamelize: 1.2.0 @@ -4233,6 +4400,10 @@ packages: engines: {node: '>=0.10.0'} dev: true + /decimal.js@10.4.3: + resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} + dev: true + /decode-uri-component@0.2.2: resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} engines: {node: '>=0.10'} @@ -4288,6 +4459,24 @@ packages: engines: {node: '>=0.10.0'} dev: true + /default-browser-id@3.0.0: + resolution: {integrity: sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==} + engines: {node: '>=12'} + dependencies: + bplist-parser: 0.2.0 + untildify: 4.0.0 + dev: true + + /default-browser@4.0.0: + resolution: {integrity: sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==} + engines: {node: '>=14.16'} + dependencies: + bundle-name: 3.0.0 + default-browser-id: 3.0.0 + execa: 7.1.1 + titleize: 3.0.0 + dev: true + /defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} dependencies: @@ -4299,9 +4488,9 @@ packages: engines: {node: '>=10'} dev: true - /define-lazy-prop@2.0.0: - resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} - engines: {node: '>=8'} + /define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} dev: true /define-properties@1.1.4: @@ -4312,14 +4501,14 @@ packages: object-keys: 1.1.1 dev: true - /degenerator@3.0.2: - resolution: {integrity: sha512-c0mef3SNQo56t6urUU6tdQAs+ThoD0o9B9MJ8HEt7NQcGEILCRFqQb7ZbP9JAv+QF1Ky5plydhMR/IrqWDm+TQ==} + /degenerator@3.0.4: + resolution: {integrity: sha512-Z66uPeBfHZAHVmue3HPfyKu2Q0rC2cRxbTOsvmU/po5fvvcx27W4mIu9n0PUlQih4oUYvcG1BsbtVv8x7KDOSw==} engines: {node: '>= 6'} dependencies: ast-types: 0.13.4 escodegen: 1.14.3 esprima: 4.0.1 - vm2: 3.9.14 + vm2: 3.9.17 dev: true /del@5.1.0: @@ -4336,6 +4525,11 @@ packages: slash: 3.0.0 dev: true + /delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dev: true + /depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -4397,6 +4591,13 @@ packages: webidl-conversions: 4.0.2 dev: true + /domexception@4.0.0: + resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==} + engines: {node: '>=12'} + dependencies: + webidl-conversions: 7.0.0 + dev: true + /domhandler@4.3.1: resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} engines: {node: '>= 4'} @@ -4595,7 +4796,7 @@ packages: dev: true /escape-string-regexp@1.0.5: - resolution: {integrity: sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=} + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} dev: true @@ -4622,6 +4823,19 @@ packages: source-map: 0.6.1 dev: true + /escodegen@2.0.0: + resolution: {integrity: sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==} + engines: {node: '>=6.0'} + hasBin: true + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionator: 0.8.3 + optionalDependencies: + source-map: 0.6.1 + dev: true + /eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.27.5)(eslint@8.38.0): resolution: {integrity: sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==} engines: {node: ^10.12.0 || >=12.0.0} @@ -4656,35 +4870,6 @@ packages: - supports-color dev: true - /eslint-module-utils@2.7.4(@typescript-eslint/parser@5.58.0)(eslint-import-resolver-node@0.3.7)(eslint@8.38.0): - resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - dependencies: - '@typescript-eslint/parser': 5.58.0(eslint@8.38.0)(typescript@5.0.4) - debug: 3.2.7 - eslint: 8.38.0 - eslint-import-resolver-node: 0.3.7 - transitivePeerDependencies: - - supports-color - dev: true - /eslint-module-utils@2.7.4(@typescript-eslint/parser@5.59.0)(eslint-import-resolver-node@0.3.7)(eslint@8.38.0): resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} engines: {node: '>=4'} @@ -4714,39 +4899,6 @@ packages: - supports-color dev: true - /eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.58.0)(eslint@8.38.0): - resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - dependencies: - '@typescript-eslint/parser': 5.58.0(eslint@8.38.0)(typescript@5.0.4) - array-includes: 3.1.6 - array.prototype.flat: 1.3.1 - array.prototype.flatmap: 1.3.1 - debug: 3.2.7 - doctrine: 2.1.0 - eslint: 8.38.0 - eslint-import-resolver-node: 0.3.7 - eslint-module-utils: 2.7.4(@typescript-eslint/parser@5.58.0)(eslint-import-resolver-node@0.3.7)(eslint@8.38.0) - has: 1.0.3 - is-core-module: 2.12.0 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.values: 1.1.6 - resolve: 1.22.1 - semver: 6.3.0 - tsconfig-paths: 3.14.1 - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - dev: true - /eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.59.0)(eslint@8.38.0): resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} engines: {node: '>=4'} @@ -4780,25 +4932,6 @@ packages: - supports-color dev: true - /eslint-plugin-jsdoc@41.1.1(eslint@8.38.0): - resolution: {integrity: sha512-dfH97DKLGtQ5dgEMzd+GSUuY+xX/yyAfjML3O0pEWmMMpylsG6Ro65s4ziYXKmixiENYK9CTQxCVRGqZUFN2Mw==} - engines: {node: ^14 || ^16 || ^17 || ^18 || ^19} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - dependencies: - '@es-joy/jsdoccomment': 0.37.0 - are-docs-informative: 0.0.2 - comment-parser: 1.3.1 - debug: 4.3.4 - escape-string-regexp: 4.0.0 - eslint: 8.38.0 - esquery: 1.5.0 - semver: 7.3.8 - spdx-expression-parse: 3.0.1 - transitivePeerDependencies: - - supports-color - dev: true - /eslint-plugin-jsdoc@43.0.6(eslint@8.38.0): resolution: {integrity: sha512-EJyrcIY4e/e51yzLLBpYX7/Ld1+08Bl/XparwHFTmQ8gUfir4wEmY2c/lj91k9+/8auKeNA5ejbyaOl42xX0AQ==} engines: {node: ^14 || ^16 || ^17 || ^18 || ^19 || ^20} @@ -5019,13 +5152,13 @@ packages: strip-final-newline: 2.0.0 dev: true - /execa@7.0.0: - resolution: {integrity: sha512-tQbH0pH/8LHTnwTrsKWideqi6rFB/QNUawEwrn+WHyz7PX1Tuz2u7wfTvbaNBdP5JD5LVWxNo8/A8CHNZ3bV6g==} + /execa@7.1.1: + resolution: {integrity: sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==} engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0} dependencies: cross-spawn: 7.0.3 get-stream: 6.0.1 - human-signals: 4.3.0 + human-signals: 4.3.1 is-stream: 3.0.0 merge-stream: 2.0.0 npm-run-path: 5.1.0 @@ -5132,7 +5265,7 @@ packages: dev: true /find-up@2.1.0: - resolution: {integrity: sha1-RdG35QbHF93UgndaK3eSCjwMV6c=} + resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} engines: {node: '>=4'} dependencies: locate-path: 2.0.0 @@ -5177,6 +5310,15 @@ packages: engines: {node: '>= 14.17'} dev: true + /form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: true + /formdata-polyfill@4.0.10: resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} engines: {node: '>=12.20.0'} @@ -5264,14 +5406,6 @@ packages: resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} dev: true - /get-intrinsic@1.1.3: - resolution: {integrity: sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==} - dependencies: - function-bind: 1.1.1 - has: 1.0.3 - has-symbols: 1.0.3 - dev: true - /get-intrinsic@1.2.0: resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==} dependencies: @@ -5473,7 +5607,7 @@ packages: dependencies: dir-glob: 3.0.1 fast-glob: 3.2.12 - ignore: 5.2.0 + ignore: 5.2.4 merge2: 1.4.1 slash: 4.0.0 dev: true @@ -5495,7 +5629,7 @@ packages: '@sindresorhus/is': 5.3.0 '@szmarczak/http-timer': 5.0.1 cacheable-lookup: 7.0.0 - cacheable-request: 10.2.8 + cacheable-request: 10.2.10 decompress-response: 6.0.0 form-data-encoder: 2.1.4 get-stream: 6.0.1 @@ -5523,7 +5657,7 @@ packages: source-map: 0.6.1 wordwrap: 1.0.0 optionalDependencies: - uglify-js: 3.17.3 + uglify-js: 3.17.4 dev: true /hard-rejection@2.1.0: @@ -5536,7 +5670,7 @@ packages: dev: true /has-flag@3.0.0: - resolution: {integrity: sha1-tdRU3CGZriJWmfNGfloH87lVuv0=} + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} dev: true @@ -5591,6 +5725,13 @@ packages: lru-cache: 6.0.0 dev: true + /html-encoding-sniffer@3.0.0: + resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==} + engines: {node: '>=12'} + dependencies: + whatwg-encoding: 2.0.0 + dev: true + /html-entities@2.3.3: resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==} dev: true @@ -5600,6 +5741,11 @@ packages: engines: {node: '>=8'} dev: true + /html-tags@3.3.1: + resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==} + engines: {node: '>=8'} + dev: true + /http-cache-semantics@4.1.1: resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} dev: true @@ -5626,6 +5772,17 @@ packages: - supports-color dev: true + /http-proxy-agent@5.0.0: + resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} + engines: {node: '>= 6'} + dependencies: + '@tootallnate/once': 2.0.0 + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + /http2-wrapper@2.2.0: resolution: {integrity: sha512-kZB0wxMo0sh1PehyjJUWRFEd99KC5TLjZ2cULC4f9iqJBAmKQQXEICjxl5iPJRwP40dpeHFqqhm7tYCvODpqpQ==} engines: {node: '>=10.19.0'} @@ -5649,8 +5806,8 @@ packages: engines: {node: '>=10.17.0'} dev: true - /human-signals@4.3.0: - resolution: {integrity: sha512-zyzVyMjpGBX2+6cDVZeFPCdtOtdsxOeseRhB9tkQ6xXmGUNrcnBzdEKPy3VPNYz+4gy1oukVOXcrJCunSyc6QQ==} + /human-signals@4.3.1: + resolution: {integrity: sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==} engines: {node: '>=14.18.0'} dev: true @@ -5661,6 +5818,13 @@ packages: safer-buffer: 2.1.2 dev: true + /iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + dev: true + /icss-replace-symbols@1.1.0: resolution: {integrity: sha512-chIaY3Vh2mh2Q3RGXttaDIzeiPvaVXJ+C4DAh/w3c37SKZ/U6PGMmuicR2EQQp9bKG8zLMCl7I+PtIoOOPp8Gg==} dev: true @@ -5683,6 +5847,11 @@ packages: engines: {node: '>= 4'} dev: true + /ignore@5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + engines: {node: '>= 4'} + dev: true + /import-cwd@3.0.0: resolution: {integrity: sha512-4pnzH16plW+hgvRECbDWpQl3cqtvSofHWh44met7ESfZ8UZOWWddm8hEyDTqREJ9RbYHY8gi8DqmaelApoOGMg==} engines: {node: '>=8'} @@ -5744,21 +5913,21 @@ packages: resolution: {integrity: sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==} dev: true - /inquirer@9.1.4: - resolution: {integrity: sha512-9hiJxE5gkK/cM2d1mTEnuurGTAoHebbkX0BYl3h7iEg7FYfuNIom+nDfBCSWtvSnoSrWCeBxqqBZu26xdlJlXA==} - engines: {node: '>=12.0.0'} + /inquirer@9.1.5: + resolution: {integrity: sha512-3ygAIh8gcZavV9bj6MTdYddG2zPSYswP808fKS46NOwlF0zZljVpnLCHODDqItWJDbDpLb3aouAxGaJbkxoppA==} + engines: {node: '>=14.18.0'} dependencies: - ansi-escapes: 6.0.0 + ansi-escapes: 6.2.0 chalk: 5.2.0 cli-cursor: 4.0.0 cli-width: 4.0.0 external-editor: 3.1.0 figures: 5.0.0 lodash: 4.17.21 - mute-stream: 0.0.8 - ora: 6.1.2 + mute-stream: 1.0.0 + ora: 6.3.0 run-async: 2.4.1 - rxjs: 7.8.0 + rxjs: 7.8.1 string-width: 5.1.2 strip-ansi: 7.0.1 through: 2.3.8 @@ -5859,6 +6028,12 @@ packages: hasBin: true dev: true + /is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + dev: true + /is-extglob@2.1.1: resolution: {integrity: sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=} engines: {node: '>=0.10.0'} @@ -5869,11 +6044,6 @@ packages: engines: {node: '>=8'} dev: true - /is-fullwidth-code-point@4.0.0: - resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} - engines: {node: '>=12'} - dev: true - /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -5888,6 +6058,14 @@ packages: html-tags: 3.2.0 dev: true + /is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + dependencies: + is-docker: 3.0.0 + dev: true + /is-installed-globally@0.4.0: resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==} engines: {node: '>=10'} @@ -5956,6 +6134,10 @@ packages: engines: {node: '>=0.10.0'} dev: true + /is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + dev: true + /is-reference@1.2.1: resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} dependencies: @@ -6072,11 +6254,11 @@ packages: dev: true /isarray@0.0.1: - resolution: {integrity: sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=} + resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} dev: true /isarray@1.0.0: - resolution: {integrity: sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=} + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} dev: true /isarray@2.0.5: @@ -6092,6 +6274,17 @@ packages: resolution: {integrity: sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=} dev: true + /issue-parser@6.0.0: + resolution: {integrity: sha512-zKa/Dxq2lGsBIXQ7CUZWTHfvxPC2ej0KfO7fIPqLlHB9J2hJ7rGhZ5rilhuufylr4RXYPzJUeFjKxz305OsNlA==} + engines: {node: '>=10.13'} + dependencies: + lodash.capitalize: 4.2.1 + lodash.escaperegexp: 4.1.2 + lodash.isplainobject: 4.0.6 + lodash.isstring: 4.0.1 + lodash.uniqby: 4.7.0 + dev: true + /iterate-iterator@1.0.2: resolution: {integrity: sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw==} dev: true @@ -6112,6 +6305,11 @@ packages: resolution: {integrity: sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==} dev: true + /js-string-escape@1.0.1: + resolution: {integrity: sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==} + engines: {node: '>= 0.8'} + dev: true + /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} dev: true @@ -6128,8 +6326,49 @@ packages: engines: {node: '>=12.0.0'} dev: true + /jsdom@21.1.1: + resolution: {integrity: sha512-Jjgdmw48RKcdAIQyUD1UdBh2ecH7VqwaXPN3ehoZN6MqgVbMn+lRm1aAT1AsdJRAJpwfa4IpwgzySn61h2qu3w==} + engines: {node: '>=14'} + peerDependencies: + canvas: ^2.5.0 + peerDependenciesMeta: + canvas: + optional: true + dependencies: + abab: 2.0.6 + acorn: 8.8.2 + acorn-globals: 7.0.1 + cssstyle: 3.0.0 + data-urls: 4.0.0 + decimal.js: 10.4.3 + domexception: 4.0.0 + escodegen: 2.0.0 + form-data: 4.0.0 + html-encoding-sniffer: 3.0.0 + http-proxy-agent: 5.0.0 + https-proxy-agent: 5.0.1 + is-potential-custom-element-name: 1.0.1 + nwsapi: 2.2.4 + parse5: 7.1.2 + rrweb-cssom: 0.6.0 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 4.1.2 + w3c-xmlserializer: 4.0.0 + webidl-conversions: 7.0.0 + whatwg-encoding: 2.0.0 + whatwg-mimetype: 3.0.0 + whatwg-url: 12.0.1 + ws: 8.13.0 + xml-name-validator: 4.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true + /jsesc@0.5.0: - resolution: {integrity: sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=} + resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} hasBin: true dev: true @@ -6185,7 +6424,7 @@ packages: dev: true /jsonfile@4.0.0: - resolution: {integrity: sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=} + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} optionalDependencies: graceful-fs: 4.2.10 dev: true @@ -6230,8 +6469,8 @@ packages: resolution: {integrity: sha512-RTSoaUAfLvpR357vWzAz/50Q/BmHfmE6ETSWfutT0AJiw10e6CmcdYRQJlLRd95B53D0Y2aD1jSxD3V3ySF+PA==} dev: true - /known-css-properties@0.25.0: - resolution: {integrity: sha512-b0/9J1O9Jcyik1GC6KC42hJ41jKwdO/Mq8Mdo5sYN+IuRTXs2YFHZC3kZSx6ueusqa95x3wLYe/ytKjbAfGixA==} + /known-css-properties@0.27.0: + resolution: {integrity: sha512-uMCj6+hZYDoffuvAJjFAPz56E9uoowFHmTkqRtRq5WyC5Q6Cu/fTZKNQpX/RbzChBYLLl3lo8CjFZBAZXq9qFg==} dev: true /language-subtag-registry@0.3.22: @@ -6252,7 +6491,7 @@ packages: dev: true /levn@0.3.0: - resolution: {integrity: sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=} + resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==} engines: {node: '>= 0.8.0'} dependencies: prelude-ls: 1.1.2 @@ -6297,7 +6536,7 @@ packages: dev: true /locate-path@2.0.0: - resolution: {integrity: sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=} + resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} engines: {node: '>=4'} dependencies: p-locate: 2.0.0 @@ -6322,8 +6561,16 @@ packages: resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} dev: true - /lodash.debounce@4.0.8: - resolution: {integrity: sha1-gteb/zCmfEAF/9XiUVMArZyk168=} + /lodash.capitalize@4.2.1: + resolution: {integrity: sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==} + dev: true + + /lodash.debounce@4.0.8: + resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} + dev: true + + /lodash.escaperegexp@4.1.2: + resolution: {integrity: sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==} dev: true /lodash.hasin@4.5.2: @@ -6346,8 +6593,12 @@ packages: resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} dev: true + /lodash.isstring@4.0.1: + resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} + dev: true + /lodash.memoize@4.1.2: - resolution: {integrity: sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=} + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} dev: true /lodash.merge@4.6.2: @@ -6366,6 +6617,10 @@ packages: resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} dev: true + /lodash.uniqby@4.7.0: + resolution: {integrity: sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==} + dev: true + /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} dev: true @@ -6427,6 +6682,13 @@ packages: '@jridgewell/sourcemap-codec': 1.4.14 dev: true + /magic-string@0.30.0: + resolution: {integrity: sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/sourcemap-codec': 1.4.14 + dev: true + /map-obj@1.0.1: resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} engines: {node: '>=0.10.0'} @@ -6441,6 +6703,13 @@ packages: resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==} dev: true + /md5-hex@3.0.1: + resolution: {integrity: sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==} + engines: {node: '>=8'} + dependencies: + blueimp-md5: 2.19.0 + dev: true + /mdn-data@2.0.14: resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==} dev: true @@ -6459,7 +6728,7 @@ packages: dependencies: '@types/minimist': 1.2.2 camelcase-keys: 6.2.2 - decamelize-keys: 1.1.0 + decamelize-keys: 1.1.1 hard-rejection: 2.1.0 minimist-options: 4.1.0 normalize-package-data: 3.0.3 @@ -6477,7 +6746,7 @@ packages: '@types/minimist': 1.2.2 camelcase-keys: 6.2.2 decamelize: 1.2.0 - decamelize-keys: 1.1.0 + decamelize-keys: 1.1.1 hard-rejection: 2.1.0 minimist-options: 4.1.0 normalize-package-data: 3.0.3 @@ -6581,13 +6850,13 @@ packages: resolution: {integrity: sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==} dev: true - /mlly@1.1.0: - resolution: {integrity: sha512-cwzBrBfwGC1gYJyfcy8TcZU1f+dbH/T+TuOhtYP2wLv/Fb51/uV7HJQfBPtEupZ2ORLRU1EKFS/QfS3eo9+kBQ==} + /mlly@1.2.0: + resolution: {integrity: sha512-+c7A3CV0KGdKcylsI6khWyts/CYrGTrRVo4R/I7u/cUsy0Conxa6LUhiEzVKIw14lc2L5aiO4+SeVe4TeGRKww==} dependencies: acorn: 8.8.2 pathe: 1.1.0 - pkg-types: 1.0.1 - ufo: 1.0.1 + pkg-types: 1.0.2 + ufo: 1.1.1 dev: true /modify-values@1.0.1: @@ -6603,8 +6872,9 @@ packages: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} dev: true - /mute-stream@0.0.8: - resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} + /mute-stream@1.0.0: + resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dev: true /nanoid@3.3.4: @@ -6613,6 +6883,12 @@ packages: hasBin: true dev: true + /nanoid@3.3.6: + resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + /natural-compare-lite@1.4.0: resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} dev: true @@ -6658,8 +6934,8 @@ packages: whatwg-url: 5.0.0 dev: true - /node-fetch@3.3.0: - resolution: {integrity: sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==} + /node-fetch@3.3.1: + resolution: {integrity: sha512-cRVc/kyto/7E5shrWca1Wsea4y6tL9iYJE5FBCius3JQfb/4P4I295PfhgbJQBLTx6lATE4z+wK0rPM4VS2uow==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: data-uri-to-buffer: 4.0.1 @@ -6696,7 +6972,7 @@ packages: dev: true /normalize-range@0.1.2: - resolution: {integrity: sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=} + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} engines: {node: '>=0.10.0'} dev: true @@ -6734,6 +7010,10 @@ packages: boolbase: 1.0.0 dev: true + /nwsapi@2.2.4: + resolution: {integrity: sha512-NHj4rzRo0tQdijE9ZqAx6kYDcoRwYwSYzCA8MY3JzfxlrvEU0jhnhJT9BhqhJs7I/dKcrDm6TyulaRqZPIhN5g==} + dev: true + /object-inspect@1.12.2: resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==} dev: true @@ -6813,12 +7093,13 @@ packages: mimic-fn: 4.0.0 dev: true - /open@8.4.2: - resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} - engines: {node: '>=12'} + /open@9.1.0: + resolution: {integrity: sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==} + engines: {node: '>=14.16'} dependencies: - define-lazy-prop: 2.0.0 - is-docker: 2.2.1 + default-browser: 4.0.0 + define-lazy-prop: 3.0.0 + is-inside-container: 1.0.0 is-wsl: 2.2.0 dev: true @@ -6851,17 +7132,17 @@ packages: word-wrap: 1.2.3 dev: true - /ora@6.1.2: - resolution: {integrity: sha512-EJQ3NiP5Xo94wJXIzAyOtSb0QEIAUu7m8t6UZ9krbz0vAJqr92JpcK/lEXg91q6B9pEGqrykkd2EQplnifDSBw==} + /ora@6.3.0: + resolution: {integrity: sha512-1/D8uRFY0ay2kgBpmAwmSA404w4OoPVhHMqRqtjvrcK/dnzcEZxMJ+V4DUbyICu8IIVRclHcOf5wlD1tMY4GUQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: - bl: 5.1.0 chalk: 5.2.0 cli-cursor: 4.0.0 - cli-spinners: 2.7.0 + cli-spinners: 2.8.0 is-interactive: 2.0.0 is-unicode-supported: 1.3.0 log-symbols: 5.1.0 + stdin-discarder: 0.1.0 strip-ansi: 7.0.1 wcwidth: 1.0.1 dev: true @@ -6918,7 +7199,7 @@ packages: dev: true /p-locate@2.0.0: - resolution: {integrity: sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=} + resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} engines: {node: '>=4'} dependencies: p-limit: 1.3.0 @@ -6991,7 +7272,7 @@ packages: resolution: {integrity: sha512-cy7u00ko2KVgBAjuhevqpPeHIkCIqPe1v24cydhWjmeuzaBfmUWFCZJ1iAh5TuVzVZoUzXIW7K8sMYOZ84uZ9Q==} engines: {node: '>= 8'} dependencies: - degenerator: 3.0.2 + degenerator: 3.0.4 ip: 1.1.8 netmask: 2.0.2 dev: true @@ -7022,7 +7303,7 @@ packages: dev: true /parse-json@4.0.0: - resolution: {integrity: sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=} + resolution: {integrity: sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==} engines: {node: '>=4'} dependencies: error-ex: 1.3.2 @@ -7051,8 +7332,14 @@ packages: parse-path: 7.0.0 dev: true + /parse5@7.1.2: + resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} + dependencies: + entities: 4.4.0 + dev: true + /path-exists@3.0.0: - resolution: {integrity: sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=} + resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} engines: {node: '>=4'} dev: true @@ -7110,12 +7397,12 @@ packages: dev: true /pify@2.3.0: - resolution: {integrity: sha1-7RQaasBDqEnqWISY59yosVMw6Qw=} + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} dev: true /pify@3.0.0: - resolution: {integrity: sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=} + resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} engines: {node: '>=4'} dev: true @@ -7124,11 +7411,11 @@ packages: engines: {node: '>=10'} dev: true - /pkg-types@1.0.1: - resolution: {integrity: sha512-jHv9HB+Ho7dj6ItwppRDDl0iZRYBD0jsakHXtFgoLr+cHSF6xC+QL54sJmWxyGxOLYSHm0afhXhXcQDQqH9z8g==} + /pkg-types@1.0.2: + resolution: {integrity: sha512-hM58GKXOcj8WTqUXnsQyJYXdeAPbythQgEF3nTcEo+nkD49chjQ9IKm/QJy9xf6JakXptz86h7ecP2024rrLaQ==} dependencies: jsonc-parser: 3.2.0 - mlly: 1.1.0 + mlly: 1.2.0 pathe: 1.1.0 dev: true @@ -7142,6 +7429,16 @@ packages: postcss-value-parser: 4.2.0 dev: true + /postcss-calc@8.2.4(postcss@8.4.23): + resolution: {integrity: sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==} + peerDependencies: + postcss: ^8.2.2 + dependencies: + postcss: 8.4.23 + postcss-selector-parser: 6.0.10 + postcss-value-parser: 4.2.0 + dev: true + /postcss-colormin@5.3.0(postcss@8.4.21): resolution: {integrity: sha512-WdDO4gOFG2Z8n4P8TWBpshnL3JpmNmJwdnfP2gbk2qBA8PWwOYcmjmI/t3CmMeL72a7Hkd+x/Mg9O2/0rD54Pg==} engines: {node: ^10 || ^12 || >=14.0} @@ -7168,6 +7465,19 @@ packages: postcss-value-parser: 4.2.0 dev: true + /postcss-colormin@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-EuO+bAUmutWoZYgHn2T1dG1pPqHU6L4TjzPlu4t1wZGXQ/fxV16xg2EJmYi0z+6r+MGV1yvpx1BHkUaRrPa2bw==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + browserslist: 4.21.5 + caniuse-api: 3.0.0 + colord: 2.9.3 + postcss: 8.4.23 + postcss-value-parser: 4.2.0 + dev: true + /postcss-convert-values@5.1.2(postcss@8.4.21): resolution: {integrity: sha512-c6Hzc4GAv95B7suy4udszX9Zy4ETyMCgFPUDtWjdFTKH1SE9eFY/jEpHSwTH1QPuwxHpWslhckUQWbNRM4ho5g==} engines: {node: ^10 || ^12 || >=14.0} @@ -7190,6 +7500,17 @@ packages: postcss-value-parser: 4.2.0 dev: true + /postcss-convert-values@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-U5D8QhVwqT++ecmy8rnTb+RL9n/B806UVaS3m60lqle4YDFcpbS3ae5bTQIh3wOGUSDHSEtMYLs/38dNG7EYFw==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + browserslist: 4.21.5 + postcss: 8.4.23 + postcss-value-parser: 4.2.0 + dev: true + /postcss-discard-comments@5.1.2(postcss@8.4.21): resolution: {integrity: sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==} engines: {node: ^10 || ^12 || >=14.0} @@ -7208,6 +7529,15 @@ packages: postcss: 8.4.21 dev: true + /postcss-discard-comments@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-p2skSGqzPMZkEQvJsgnkBhCn8gI7NzRH2683EEjrIkoMiwRELx68yoUJ3q3DGSGuQ8Ug9Gsn+OuDr46yfO+eFw==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + postcss: 8.4.23 + dev: true + /postcss-discard-duplicates@5.1.0(postcss@8.4.21): resolution: {integrity: sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==} engines: {node: ^10 || ^12 || >=14.0} @@ -7226,6 +7556,15 @@ packages: postcss: 8.4.21 dev: true + /postcss-discard-duplicates@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-bU1SXIizMLtDW4oSsi5C/xHKbhLlhek/0/yCnoMQany9k3nPBq+Ctsv/9oMmyqbR96HYHxZcHyK2HR5P/mqoGA==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + postcss: 8.4.23 + dev: true + /postcss-discard-empty@5.1.1(postcss@8.4.21): resolution: {integrity: sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==} engines: {node: ^10 || ^12 || >=14.0} @@ -7244,6 +7583,15 @@ packages: postcss: 8.4.21 dev: true + /postcss-discard-empty@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-b+h1S1VT6dNhpcg+LpyiUrdnEZfICF0my7HAKgJixJLW7BnNmpRH34+uw/etf5AhOlIhIAuXApSzzDzMI9K/gQ==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + postcss: 8.4.23 + dev: true + /postcss-discard-overridden@5.1.0(postcss@8.4.21): resolution: {integrity: sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==} engines: {node: ^10 || ^12 || >=14.0} @@ -7262,6 +7610,15 @@ packages: postcss: 8.4.21 dev: true + /postcss-discard-overridden@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-4VELwssYXDFigPYAZ8vL4yX4mUepF/oCBeeIT4OXsJPYOtvJumyz9WflmJWTfDwCUcpDR+z0zvCWBXgTx35SVw==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + postcss: 8.4.23 + dev: true + /postcss-import@15.1.0(postcss@8.4.21): resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} engines: {node: '>=14.0.0'} @@ -7274,6 +7631,18 @@ packages: resolve: 1.22.1 dev: true + /postcss-import@15.1.0(postcss@8.4.23): + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + dependencies: + postcss: 8.4.23 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.1 + dev: true + /postcss-load-config@3.1.4(postcss@8.4.21): resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} engines: {node: '>= 10'} @@ -7317,6 +7686,17 @@ packages: stylehacks: 6.0.0(postcss@8.4.21) dev: true + /postcss-merge-longhand@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-4VSfd1lvGkLTLYcxFuISDtWUfFS4zXe0FpF149AyziftPFQIWxjvFSKhA4MIxMe4XM3yTDgQMbSNgzIVxChbIg==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + postcss: 8.4.23 + postcss-value-parser: 4.2.0 + stylehacks: 6.0.0(postcss@8.4.23) + dev: true + /postcss-merge-rules@5.1.2(postcss@8.4.21): resolution: {integrity: sha512-zKMUlnw+zYCWoPN6yhPjtcEdlJaMUZ0WyVcxTAmw3lkkN/NDMRkOkiuctQEoWAOvH7twaxUUdvBWl0d4+hifRQ==} engines: {node: ^10 || ^12 || >=14.0} @@ -7343,6 +7723,19 @@ packages: postcss-selector-parser: 6.0.10 dev: true + /postcss-merge-rules@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-rCXkklftzEkniyv3f4mRCQzxD6oE4Quyh61uyWTUbCJ26Pv2hoz+fivJSsSBWxDBeScR4fKCfF3HHTcD7Ybqnw==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + browserslist: 4.21.5 + caniuse-api: 3.0.0 + cssnano-utils: 4.0.0(postcss@8.4.23) + postcss: 8.4.23 + postcss-selector-parser: 6.0.10 + dev: true + /postcss-minify-font-values@5.1.0(postcss@8.4.21): resolution: {integrity: sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==} engines: {node: ^10 || ^12 || >=14.0} @@ -7363,6 +7756,16 @@ packages: postcss-value-parser: 4.2.0 dev: true + /postcss-minify-font-values@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-zNRAVtyh5E8ndZEYXA4WS8ZYsAp798HiIQ1V2UF/C/munLp2r1UGHwf1+6JFu7hdEhJFN+W1WJQKBrtjhFgEnA==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + postcss: 8.4.23 + postcss-value-parser: 4.2.0 + dev: true + /postcss-minify-gradients@5.1.1(postcss@8.4.21): resolution: {integrity: sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==} engines: {node: ^10 || ^12 || >=14.0} @@ -7387,6 +7790,18 @@ packages: postcss-value-parser: 4.2.0 dev: true + /postcss-minify-gradients@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-wO0F6YfVAR+K1xVxF53ueZJza3L+R3E6cp0VwuXJQejnNUH0DjcAFe3JEBeTY1dLwGa0NlDWueCA1VlEfiKgAA==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + colord: 2.9.3 + cssnano-utils: 4.0.0(postcss@8.4.23) + postcss: 8.4.23 + postcss-value-parser: 4.2.0 + dev: true + /postcss-minify-params@5.1.3(postcss@8.4.21): resolution: {integrity: sha512-bkzpWcjykkqIujNL+EVEPOlLYi/eZ050oImVtHU7b4lFS82jPnsCb44gvC6pxaNt38Els3jWYDHTjHKf0koTgg==} engines: {node: ^10 || ^12 || >=14.0} @@ -7411,6 +7826,18 @@ packages: postcss-value-parser: 4.2.0 dev: true + /postcss-minify-params@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-Fz/wMQDveiS0n5JPcvsMeyNXOIMrwF88n7196puSuQSWSa+/Ofc1gDOSY2xi8+A4PqB5dlYCKk/WfqKqsI+ReQ==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + browserslist: 4.21.5 + cssnano-utils: 4.0.0(postcss@8.4.23) + postcss: 8.4.23 + postcss-value-parser: 4.2.0 + dev: true + /postcss-minify-selectors@5.2.1(postcss@8.4.21): resolution: {integrity: sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==} engines: {node: ^10 || ^12 || >=14.0} @@ -7431,6 +7858,16 @@ packages: postcss-selector-parser: 6.0.10 dev: true + /postcss-minify-selectors@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-ec/q9JNCOC2CRDNnypipGfOhbYPuUkewGwLnbv6omue/PSASbHSU7s6uSQ0tcFRVv731oMIx8k0SP4ZX6be/0g==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + postcss: 8.4.23 + postcss-selector-parser: 6.0.10 + dev: true + /postcss-modules-extract-imports@3.0.0(postcss@8.4.21): resolution: {integrity: sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==} engines: {node: ^10 || ^12 || >= 14} @@ -7499,6 +7936,17 @@ packages: postcss-selector-parser: 6.0.10 dev: true + /postcss-nesting@11.2.2(postcss@8.4.23): + resolution: {integrity: sha512-aOTiUniAB1bcPE6GGiynWRa6PZFPhOTAm5q3q5cem6QeSijIHHkWr6gs65ukCZMXeak8yXeZVbBJET3VM+HlhA==} + engines: {node: ^14 || ^16 || >=18} + peerDependencies: + postcss: ^8.4 + dependencies: + '@csstools/selector-specificity': 2.0.2(postcss-selector-parser@6.0.10)(postcss@8.4.23) + postcss: 8.4.23 + postcss-selector-parser: 6.0.10 + dev: true + /postcss-normalize-charset@5.1.0(postcss@8.4.21): resolution: {integrity: sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==} engines: {node: ^10 || ^12 || >=14.0} @@ -7517,6 +7965,15 @@ packages: postcss: 8.4.21 dev: true + /postcss-normalize-charset@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-cqundwChbu8yO/gSWkuFDmKrCZ2vJzDAocheT2JTd0sFNA4HMGoKMfbk2B+J0OmO0t5GUkiAkSM5yF2rSLUjgQ==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + postcss: 8.4.23 + dev: true + /postcss-normalize-display-values@5.1.0(postcss@8.4.21): resolution: {integrity: sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==} engines: {node: ^10 || ^12 || >=14.0} @@ -7537,6 +7994,16 @@ packages: postcss-value-parser: 4.2.0 dev: true + /postcss-normalize-display-values@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-Qyt5kMrvy7dJRO3OjF7zkotGfuYALETZE+4lk66sziWSPzlBEt7FrUshV6VLECkI4EN8Z863O6Nci4NXQGNzYw==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + postcss: 8.4.23 + postcss-value-parser: 4.2.0 + dev: true + /postcss-normalize-positions@5.1.1(postcss@8.4.21): resolution: {integrity: sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==} engines: {node: ^10 || ^12 || >=14.0} @@ -7557,6 +8024,16 @@ packages: postcss-value-parser: 4.2.0 dev: true + /postcss-normalize-positions@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-mPCzhSV8+30FZyWhxi6UoVRYd3ZBJgTRly4hOkaSifo0H+pjDYcii/aVT4YE6QpOil15a5uiv6ftnY3rm0igPg==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + postcss: 8.4.23 + postcss-value-parser: 4.2.0 + dev: true + /postcss-normalize-repeat-style@5.1.1(postcss@8.4.21): resolution: {integrity: sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==} engines: {node: ^10 || ^12 || >=14.0} @@ -7577,6 +8054,16 @@ packages: postcss-value-parser: 4.2.0 dev: true + /postcss-normalize-repeat-style@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-50W5JWEBiOOAez2AKBh4kRFm2uhrT3O1Uwdxz7k24aKtbD83vqmcVG7zoIwo6xI2FZ/HDlbrCopXhLeTpQib1A==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + postcss: 8.4.23 + postcss-value-parser: 4.2.0 + dev: true + /postcss-normalize-string@5.1.0(postcss@8.4.21): resolution: {integrity: sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==} engines: {node: ^10 || ^12 || >=14.0} @@ -7597,6 +8084,16 @@ packages: postcss-value-parser: 4.2.0 dev: true + /postcss-normalize-string@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-KWkIB7TrPOiqb8ZZz6homet2KWKJwIlysF5ICPZrXAylGe2hzX/HSf4NTX2rRPJMAtlRsj/yfkrWGavFuB+c0w==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + postcss: 8.4.23 + postcss-value-parser: 4.2.0 + dev: true + /postcss-normalize-timing-functions@5.1.0(postcss@8.4.21): resolution: {integrity: sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==} engines: {node: ^10 || ^12 || >=14.0} @@ -7617,6 +8114,16 @@ packages: postcss-value-parser: 4.2.0 dev: true + /postcss-normalize-timing-functions@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-tpIXWciXBp5CiFs8sem90IWlw76FV4oi6QEWfQwyeREVwUy39VSeSqjAT7X0Qw650yAimYW5gkl2Gd871N5SQg==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + postcss: 8.4.23 + postcss-value-parser: 4.2.0 + dev: true + /postcss-normalize-unicode@5.1.0(postcss@8.4.21): resolution: {integrity: sha512-J6M3MizAAZ2dOdSjy2caayJLQT8E8K9XjLce8AUQMwOrCvjCHv24aLC/Lps1R1ylOfol5VIDMaM/Lo9NGlk1SQ==} engines: {node: ^10 || ^12 || >=14.0} @@ -7639,6 +8146,17 @@ packages: postcss-value-parser: 4.2.0 dev: true + /postcss-normalize-unicode@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-ui5crYkb5ubEUDugDc786L/Me+DXp2dLg3fVJbqyAl0VPkAeALyAijF2zOsnZyaS1HyfPuMH0DwyY18VMFVNkg==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + browserslist: 4.21.5 + postcss: 8.4.23 + postcss-value-parser: 4.2.0 + dev: true + /postcss-normalize-url@5.1.0(postcss@8.4.21): resolution: {integrity: sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==} engines: {node: ^10 || ^12 || >=14.0} @@ -7660,6 +8178,16 @@ packages: postcss-value-parser: 4.2.0 dev: true + /postcss-normalize-url@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-98mvh2QzIPbb02YDIrYvAg4OUzGH7s1ZgHlD3fIdTHLgPLRpv1ZTKJDnSAKr4Rt21ZQFzwhGMXxpXlfrUBKFHw==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + postcss: 8.4.23 + postcss-value-parser: 4.2.0 + dev: true + /postcss-normalize-whitespace@5.1.1(postcss@8.4.21): resolution: {integrity: sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==} engines: {node: ^10 || ^12 || >=14.0} @@ -7680,6 +8208,16 @@ packages: postcss-value-parser: 4.2.0 dev: true + /postcss-normalize-whitespace@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-7cfE1AyLiK0+ZBG6FmLziJzqQCpTQY+8XjMhMAz8WSBSCsCNNUKujgIgjCAmDT3cJ+3zjTXFkoD15ZPsckArVw==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + postcss: 8.4.23 + postcss-value-parser: 4.2.0 + dev: true + /postcss-ordered-values@5.1.3(postcss@8.4.21): resolution: {integrity: sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==} engines: {node: ^10 || ^12 || >=14.0} @@ -7702,6 +8240,17 @@ packages: postcss-value-parser: 4.2.0 dev: true + /postcss-ordered-values@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-K36XzUDpvfG/nWkjs6d1hRBydeIxGpKS2+n+ywlKPzx1nMYDYpoGbcjhj5AwVYJK1qV2/SDoDEnHzlPD6s3nMg==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + cssnano-utils: 4.0.0(postcss@8.4.23) + postcss: 8.4.23 + postcss-value-parser: 4.2.0 + dev: true + /postcss-reduce-initial@5.1.0(postcss@8.4.21): resolution: {integrity: sha512-5OgTUviz0aeH6MtBjHfbr57tml13PuedK/Ecg8szzd4XRMbYxH4572JFG067z+FqBIf6Zp/d+0581glkvvWMFw==} engines: {node: ^10 || ^12 || >=14.0} @@ -7724,6 +8273,17 @@ packages: postcss: 8.4.21 dev: true + /postcss-reduce-initial@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-s2UOnidpVuXu6JiiI5U+fV2jamAw5YNA9Fdi/GRK0zLDLCfXmSGqQtzpUPtfN66RtCbb9fFHoyZdQaxOB3WxVA==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + browserslist: 4.21.5 + caniuse-api: 3.0.0 + postcss: 8.4.23 + dev: true + /postcss-reduce-transforms@5.1.0(postcss@8.4.21): resolution: {integrity: sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==} engines: {node: ^10 || ^12 || >=14.0} @@ -7744,17 +8304,27 @@ packages: postcss-value-parser: 4.2.0 dev: true + /postcss-reduce-transforms@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-FQ9f6xM1homnuy1wLe9lP1wujzxnwt1EwiigtWwuyf8FsqqXUDUp2Ulxf9A5yjlUOTdCJO6lonYjg1mgqIIi2w==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + postcss: 8.4.23 + postcss-value-parser: 4.2.0 + dev: true + /postcss-resolve-nested-selector@0.1.1: resolution: {integrity: sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw==} dev: true - /postcss-safe-parser@6.0.0(postcss@8.4.17): + /postcss-safe-parser@6.0.0(postcss@8.4.23): resolution: {integrity: sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==} engines: {node: '>=12.0'} peerDependencies: postcss: ^8.3.3 dependencies: - postcss: 8.4.17 + postcss: 8.4.23 dev: true /postcss-selector-parser@6.0.10: @@ -7765,12 +8335,20 @@ packages: util-deprecate: 1.0.2 dev: true - /postcss-sorting@7.0.1(postcss@8.4.17): - resolution: {integrity: sha512-iLBFYz6VRYyLJEJsBJ8M3TCqNcckVzz4wFounSc5Oez35ogE/X+aoC5fFu103Ot7NyvjU3/xqIXn93Gp3kJk4g==} + /postcss-selector-parser@6.0.11: + resolution: {integrity: sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==} + engines: {node: '>=4'} + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + dev: true + + /postcss-sorting@8.0.2(postcss@8.4.21): + resolution: {integrity: sha512-M9dkSrmU00t/jK7rF6BZSZauA5MAaBW4i5EnJXspMwt4iqTh/L9j6fgMnbElEOfyRyfLfVbIHj/R52zHzAPe1Q==} peerDependencies: - postcss: ^8.3.9 + postcss: ^8.4.20 dependencies: - postcss: 8.4.17 + postcss: 8.4.21 dev: true /postcss-svgo@5.1.0(postcss@8.4.21): @@ -7795,6 +8373,17 @@ packages: svgo: 3.0.2 dev: true + /postcss-svgo@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-r9zvj/wGAoAIodn84dR/kFqwhINp5YsJkLoujybWG59grR/IHx+uQ2Zo+IcOwM0jskfYX3R0mo+1Kip1VSNcvw==} + engines: {node: ^14 || ^16 || >= 18} + peerDependencies: + postcss: ^8.2.15 + dependencies: + postcss: 8.4.23 + postcss-value-parser: 4.2.0 + svgo: 3.0.2 + dev: true + /postcss-unique-selectors@5.1.1(postcss@8.4.21): resolution: {integrity: sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==} engines: {node: ^10 || ^12 || >=14.0} @@ -7815,12 +8404,22 @@ packages: postcss-selector-parser: 6.0.10 dev: true + /postcss-unique-selectors@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-EPQzpZNxOxP7777t73RQpZE5e9TrnCrkvp7AH7a0l89JmZiPnS82y216JowHXwpBCQitfyxrof9TK3rYbi7/Yw==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + postcss: 8.4.23 + postcss-selector-parser: 6.0.10 + dev: true + /postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} dev: true - /postcss@8.4.17: - resolution: {integrity: sha512-UNxNOLQydcOFi41yHNMcKRZ39NeXlr8AxGuZJsdub8vIb12fHzcq37DTU/QtbI6WLxNg2gF9Z+8qtRwTj1UI1Q==} + /postcss@8.4.21: + resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} engines: {node: ^10 || ^12 || >=14} dependencies: nanoid: 3.3.4 @@ -7828,17 +8427,17 @@ packages: source-map-js: 1.0.2 dev: true - /postcss@8.4.21: - resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} + /postcss@8.4.23: + resolution: {integrity: sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==} engines: {node: ^10 || ^12 || >=14} dependencies: - nanoid: 3.3.4 + nanoid: 3.3.6 picocolors: 1.0.0 source-map-js: 1.0.2 dev: true /prelude-ls@1.1.2: - resolution: {integrity: sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=} + resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} engines: {node: '>= 0.8.0'} dev: true @@ -7936,7 +8535,7 @@ packages: call-bind: 1.0.2 define-properties: 1.1.4 es-abstract: 1.20.4 - get-intrinsic: 1.1.3 + get-intrinsic: 1.2.0 iterate-value: 1.0.2 dev: true @@ -7973,11 +8572,20 @@ packages: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} dev: true + /psl@1.9.0: + resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} + dev: true + /punycode@2.1.1: resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} engines: {node: '>=6'} dev: true + /punycode@2.3.0: + resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} + engines: {node: '>=6'} + dev: true + /pupa@3.1.0: resolution: {integrity: sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==} engines: {node: '>=12.20'} @@ -8000,6 +8608,10 @@ packages: strict-uri-encode: 2.0.0 dev: true + /querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + dev: true + /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true @@ -8089,8 +8701,8 @@ packages: string_decoder: 0.10.31 dev: true - /readable-stream@2.3.7: - resolution: {integrity: sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==} + /readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} dependencies: core-util-is: 1.0.3 inherits: 2.0.4 @@ -8101,8 +8713,8 @@ packages: util-deprecate: 1.0.2 dev: true - /readable-stream@3.6.0: - resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==} + /readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} dependencies: inherits: 2.0.4 @@ -8179,7 +8791,7 @@ packages: resolution: {integrity: sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==} engines: {node: '>=14'} dependencies: - '@pnpm/npm-conf': 2.1.0 + '@pnpm/npm-conf': 2.1.1 dev: true /registry-url@6.0.1: @@ -8196,8 +8808,8 @@ packages: jsesc: 0.5.0 dev: true - /release-it@15.8.0: - resolution: {integrity: sha512-eJwYY/vXefcnWn7OHlZRcQJYPSJw/fdO+29C/Re5MZE8FZReCHu+EYq3yB0Bm39/3cTVz/5I/2Fk5rtAsVFU1g==} + /release-it@15.10.1: + resolution: {integrity: sha512-Wkk4aFHSo27vQwHIlcEy77lJwnQlh4UDQckc53gh5tKo7F22mAUEAe8SYQZJcFh7icdkf0OV70onhB1dDmeClA==} engines: {node: '>=14.9'} hasBin: true dependencies: @@ -8205,19 +8817,20 @@ packages: '@octokit/rest': 19.0.7 async-retry: 1.3.3 chalk: 5.2.0 - cosmiconfig: 8.1.0 - execa: 7.0.0 + cosmiconfig: 8.1.3 + execa: 7.1.1 git-url-parse: 13.1.0 globby: 13.1.3 got: 12.6.0 - inquirer: 9.1.4 + inquirer: 9.1.5 is-ci: 3.0.1 + issue-parser: 6.0.0 lodash: 4.17.21 mime-types: 2.1.35 new-github-release-url: 2.0.0 - node-fetch: 3.3.0 - open: 8.4.2 - ora: 6.1.2 + node-fetch: 3.3.1 + open: 9.1.0 + ora: 6.3.0 os-name: 5.1.0 promise.allsettled: 1.0.6 proxy-agent: 5.0.0 @@ -8242,6 +8855,10 @@ packages: engines: {node: '>=0.10.0'} dev: true + /requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + dev: true + /resolve-alpn@1.2.1: resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} dev: true @@ -8464,19 +9081,6 @@ packages: typescript: 4.9.5 dev: true - /rollup-plugin-userscript-metablock@0.3.1: - resolution: {integrity: sha512-FwGgBQ8oD9MYkUI2CRPD4TJr3hV0UP4YCOGFQDK8PqMZLD6IbPvuraG3qhMCFhukzeTgfEs6uGsUO0xujeJEFw==} - dependencies: - chalk: 4.1.2 - debug: 4.3.4 - js-yaml: 4.1.0 - magic-string: 0.25.9 - semver: 7.3.8 - valid-url: 1.0.9 - transitivePeerDependencies: - - supports-color - dev: true - /rollup-plugin-userscript-metablock@0.3.2: resolution: {integrity: sha512-G0IgeqOWqGvE3dulcA0vVdwqYFfm0j+vfXMGBj8GWt8G/FqOebIua3tFbHyPM6aGcxwcEH9F33CwDx9WpUGerA==} dependencies: @@ -8533,6 +9137,17 @@ packages: fsevents: 2.3.2 dev: true + /rrweb-cssom@0.6.0: + resolution: {integrity: sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==} + dev: true + + /run-applescript@5.0.0: + resolution: {integrity: sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==} + engines: {node: '>=12'} + dependencies: + execa: 5.1.1 + dev: true + /run-async@2.4.1: resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} engines: {node: '>=0.12.0'} @@ -8544,8 +9159,8 @@ packages: queue-microtask: 1.2.3 dev: true - /rxjs@7.8.0: - resolution: {integrity: sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==} + /rxjs@7.8.1: + resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} dependencies: tslib: 2.5.0 dev: true @@ -8574,6 +9189,13 @@ packages: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} dev: true + /saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + dependencies: + xmlchars: 2.2.0 + dev: true + /semver-diff@4.0.0: resolution: {integrity: sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==} engines: {node: '>=12'} @@ -8653,6 +9275,11 @@ packages: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: true + /signal-exit@4.0.1: + resolution: {integrity: sha512-uUWsN4aOxJAS8KOuf3QMyFtgm1pkb6I+KRZbRF/ghdf5T7sM+B1lLLzPDxswUjkmHyxQAVzEgG35E3NzDM9GVw==} + engines: {node: '>=14'} + dev: true + /slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -8672,14 +9299,6 @@ packages: is-fullwidth-code-point: 3.0.0 dev: true - /slice-ansi@5.0.0: - resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} - engines: {node: '>=12'} - dependencies: - ansi-styles: 6.2.1 - is-fullwidth-code-point: 4.0.0 - dev: true - /smart-buffer@4.2.0: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} @@ -8759,8 +9378,8 @@ packages: resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} dev: true - /spdx-correct@3.1.1: - resolution: {integrity: sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==} + /spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} dependencies: spdx-expression-parse: 3.0.1 spdx-license-ids: 3.0.12 @@ -8789,7 +9408,7 @@ packages: /split2@3.2.2: resolution: {integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==} dependencies: - readable-stream: 3.6.0 + readable-stream: 3.6.2 dev: true /split@1.0.1: @@ -8816,6 +9435,13 @@ packages: resolution: {integrity: sha512-uUZI65yrV2Qva5gqE0+A7uVAvO40iPo6jGhs7s8keRfHCmtg+uB2X6EiLGCI9IgL1J17xGhvoOqSz79lzICPTA==} dev: true + /stdin-discarder@0.1.0: + resolution: {integrity: sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + bl: 5.1.0 + dev: true + /stop-iteration-iterator@1.0.0: resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} engines: {node: '>= 0.4'} @@ -8919,7 +9545,7 @@ packages: dev: true /strip-json-comments@2.0.1: - resolution: {integrity: sha1-PFMZQukIwml8DsNEhYwobHygpgo=} + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} engines: {node: '>=0.10.0'} dev: true @@ -8970,91 +9596,107 @@ packages: postcss-selector-parser: 6.0.10 dev: true - /stylelint-config-clean-order@0.9.0(stylelint@14.13.0): - resolution: {integrity: sha512-7h00qcvnFdUALMFELr5NWbK3tH3MJo1EFIo31fMcAu3pLg2BI5/NCOLSHsTja6hHS5KI4sPJk4xIt/sp90BQsw==} + /stylehacks@6.0.0(postcss@8.4.23): + resolution: {integrity: sha512-+UT589qhHPwz6mTlCLSt/vMNTJx8dopeJlZAlBMJPWA3ORqu6wmQY7FBXf+qD+FsqoBJODyqNxOUP3jdntFRdw==} + engines: {node: ^14 || ^16 || >=18.0} + peerDependencies: + postcss: ^8.2.15 + dependencies: + browserslist: 4.21.5 + postcss: 8.4.23 + postcss-selector-parser: 6.0.10 + dev: true + + /stylelint-config-clean-order@5.0.1(stylelint@15.6.0): + resolution: {integrity: sha512-zKLXjTgrkZqiml0VXv7Syl11XLpzRErW+1/qSEjIQ+aHAFjGuRq6Uwal9OzxtDHvpoIhlc4wCYjougWDuLN5aA==} peerDependencies: stylelint: '>=14' dependencies: - stylelint: 14.13.0 - stylelint-order: 5.0.0(stylelint@14.13.0) + stylelint: 15.6.0 + stylelint-order: 6.0.3(stylelint@15.6.0) dev: true - /stylelint-config-prettier@9.0.3(stylelint@14.13.0): - resolution: {integrity: sha512-5n9gUDp/n5tTMCq1GLqSpA30w2sqWITSSEiAWQlpxkKGAUbjcemQ0nbkRvRUa0B1LgD3+hCvdL7B1eTxy1QHJg==} + /stylelint-config-prettier@9.0.5(stylelint@15.6.0): + resolution: {integrity: sha512-U44lELgLZhbAD/xy/vncZ2Pq8sh2TnpiPvo38Ifg9+zeioR+LAkHu0i6YORIOxFafZoVg0xqQwex6e6F25S5XA==} engines: {node: '>= 12'} hasBin: true peerDependencies: - stylelint: '>=11.0.0' + stylelint: '>= 11.x < 15' dependencies: - stylelint: 14.13.0 + stylelint: 15.6.0 dev: true - /stylelint-config-recess-order@3.0.0(stylelint@14.13.0): - resolution: {integrity: sha512-uNXrlDz570Q7HJlrq8mNjgfO/xlKIh2hKVKEFMTG1/ih/6tDLcTbuvO1Zoo2dnQay990OAkWLDpTDOorB+hmBw==} + /stylelint-config-recess-order@4.0.0(stylelint@15.6.0): + resolution: {integrity: sha512-sOb+OofMryBR91CbzgV2FavpONqiIeAE7cfrgyUHqePblWBKsYzoUuWThI5EjPRA7KKeovm6ykr7twWYLeafPQ==} peerDependencies: - stylelint: '>=14' + stylelint: '>=15' dependencies: - stylelint: 14.13.0 - stylelint-order: 5.0.0(stylelint@14.13.0) + stylelint: 15.6.0 + stylelint-order: 6.0.3(stylelint@15.6.0) dev: true - /stylelint-config-recommended@9.0.0(stylelint@14.13.0): - resolution: {integrity: sha512-9YQSrJq4NvvRuTbzDsWX3rrFOzOlYBmZP+o513BJN/yfEmGSr0AxdvrWs0P/ilSpVV/wisamAHu5XSk8Rcf4CQ==} + /stylelint-config-recommended@12.0.0(stylelint@15.6.0): + resolution: {integrity: sha512-x6x8QNARrGO2sG6iURkzqL+Dp+4bJorPMMRNPScdvaUK8PsynriOcMW7AFDKqkWAS5wbue/u8fUT/4ynzcmqdQ==} peerDependencies: - stylelint: ^14.10.0 + stylelint: ^15.5.0 dependencies: - stylelint: 14.13.0 + stylelint: 15.6.0 dev: true - /stylelint-config-standard@28.0.0(stylelint@14.13.0): - resolution: {integrity: sha512-q/StuowDdDmFCravzGHAwgS9pjX0bdOQUEBBDIkIWsQuYGgYz/xsO8CM6eepmIQ1fc5bKdDVimlJZ6MoOUcJ5Q==} + /stylelint-config-standard@33.0.0(stylelint@15.6.0): + resolution: {integrity: sha512-eyxnLWoXImUn77+ODIuW9qXBDNM+ALN68L3wT1lN2oNspZ7D9NVGlNHb2QCUn4xDug6VZLsh0tF8NyoYzkgTzg==} peerDependencies: - stylelint: ^14.11.0 + stylelint: ^15.5.0 dependencies: - stylelint: 14.13.0 - stylelint-config-recommended: 9.0.0(stylelint@14.13.0) + stylelint: 15.6.0 + stylelint-config-recommended: 12.0.0(stylelint@15.6.0) dev: true - /stylelint-high-performance-animation@1.6.0(stylelint@14.13.0): - resolution: {integrity: sha512-RW3XbNLMoKcqY97NTNLXzfg4IGzCfaIf+s4aQem7BzN5IYqYLdYuU1WCqMCoiZHRILQIkrkNvcaQOAu7bA9qxw==} + /stylelint-high-performance-animation@1.8.0(stylelint@15.6.0): + resolution: {integrity: sha512-wxHt+F7Z54mtGZpbdMwUtpfQwr81uiml39EFCCdZAbVnEO7Wl0Mh5ncmgbxH42xpB5z79eIgHI62qtKfUmWzhg==} peerDependencies: - stylelint: ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0 + stylelint: ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 dependencies: - stylelint: 14.13.0 + postcss-value-parser: 4.2.0 + stylelint: 15.6.0 dev: true - /stylelint-order@5.0.0(stylelint@14.13.0): - resolution: {integrity: sha512-OWQ7pmicXufDw5BlRqzdz3fkGKJPgLyDwD1rFY3AIEfIH/LQY38Vu/85v8/up0I+VPiuGRwbc2Hg3zLAsJaiyw==} + /stylelint-order@6.0.3(stylelint@15.6.0): + resolution: {integrity: sha512-1j1lOb4EU/6w49qZeT2SQVJXm0Ht+Qnq9GMfUa3pMwoyojIWfuA+JUDmoR97Bht1RLn4ei0xtLGy87M7d29B1w==} peerDependencies: - stylelint: ^14.0.0 + stylelint: ^14.0.0 || ^15.0.0 dependencies: - postcss: 8.4.17 - postcss-sorting: 7.0.1(postcss@8.4.17) - stylelint: 14.13.0 + postcss: 8.4.21 + postcss-sorting: 8.0.2(postcss@8.4.21) + stylelint: 15.6.0 dev: true - /stylelint-prettier@2.0.0(prettier@2.8.7)(stylelint@14.13.0): - resolution: {integrity: sha512-jvT3G+9lopkeB0ARmDPszyfaOnvnIF+30QCjZxyt7E6fynI1T9mOKgYDNb9bXX17M7PXMZaX3j/26wqakjp1tw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + /stylelint-prettier@3.0.0(prettier@2.8.7)(stylelint@15.6.0): + resolution: {integrity: sha512-kIks1xw6np0zElokMT2kP6ar3S4MBoj6vUtPJuND1pFELMpZxVS/0uHPR4HDAVn0WAD3I5oF0IA3qBFxBpMkLg==} + engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: prettier: '>=2.0.0' stylelint: '>=14.0.0' dependencies: prettier: 2.8.7 prettier-linter-helpers: 1.0.0 - stylelint: 14.13.0 + stylelint: 15.6.0 dev: true - /stylelint@14.13.0: - resolution: {integrity: sha512-NJSAdloiAB/jgVJKxMR90mWlctvmeBFGFVUvyKngi9+j/qPSJ5ZB+u8jOmGbLTnS7OHrII9NFGehPRyar8U5vg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + /stylelint@15.6.0: + resolution: {integrity: sha512-Cqzpc8tvJm77KaM8qUbhpJ/UYK55Ia0whQXj4b9IId9dlPICO7J8Lyo15SZWiHxKjlvy3p5FQor/3n6i8ignXg==} + engines: {node: ^14.13.1 || >=16.0.0} hasBin: true dependencies: - '@csstools/selector-specificity': 2.0.2(postcss-selector-parser@6.0.10)(postcss@8.4.17) + '@csstools/css-parser-algorithms': 2.1.1(@csstools/css-tokenizer@2.1.1) + '@csstools/css-tokenizer': 2.1.1 + '@csstools/media-query-list-parser': 2.0.4(@csstools/css-parser-algorithms@2.1.1)(@csstools/css-tokenizer@2.1.1) + '@csstools/selector-specificity': 2.2.0(postcss-selector-parser@6.0.11) balanced-match: 2.0.0 colord: 2.9.3 - cosmiconfig: 7.0.1 + cosmiconfig: 8.1.3 css-functions-list: 3.1.0 + css-tree: 2.3.1 debug: 4.3.4 fast-glob: 3.2.12 fastest-levenshtein: 1.0.16 @@ -9062,32 +9704,32 @@ packages: global-modules: 2.0.0 globby: 11.1.0 globjoin: 0.1.4 - html-tags: 3.2.0 - ignore: 5.2.0 + html-tags: 3.3.1 + ignore: 5.2.4 import-lazy: 4.0.0 imurmurhash: 0.1.4 is-plain-object: 5.0.0 - known-css-properties: 0.25.0 + known-css-properties: 0.27.0 mathml-tag-names: 2.1.3 meow: 9.0.0 micromatch: 4.0.5 normalize-path: 3.0.0 picocolors: 1.0.0 - postcss: 8.4.17 + postcss: 8.4.23 postcss-media-query-parser: 0.2.3 postcss-resolve-nested-selector: 0.1.1 - postcss-safe-parser: 6.0.0(postcss@8.4.17) - postcss-selector-parser: 6.0.10 + postcss-safe-parser: 6.0.0(postcss@8.4.23) + postcss-selector-parser: 6.0.11 postcss-value-parser: 4.2.0 resolve-from: 5.0.0 string-width: 4.2.3 strip-ansi: 6.0.1 style-search: 0.1.0 - supports-hyperlinks: 2.3.0 + supports-hyperlinks: 3.0.0 svg-tags: 1.0.0 - table: 6.8.0 + table: 6.8.1 v8-compile-cache: 2.3.0 - write-file-atomic: 4.0.2 + write-file-atomic: 5.0.1 transitivePeerDependencies: - supports-color dev: true @@ -9106,9 +9748,9 @@ packages: has-flag: 4.0.0 dev: true - /supports-hyperlinks@2.3.0: - resolution: {integrity: sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==} - engines: {node: '>=8'} + /supports-hyperlinks@3.0.0: + resolution: {integrity: sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==} + engines: {node: '>=14.18'} dependencies: has-flag: 4.0.0 supports-color: 7.2.0 @@ -9154,11 +9796,15 @@ packages: picocolors: 1.0.0 dev: true - /table@6.8.0: - resolution: {integrity: sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==} + /symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + dev: true + + /table@6.8.1: + resolution: {integrity: sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==} engines: {node: '>=10.0.0'} dependencies: - ajv: 8.11.0 + ajv: 8.12.0 lodash.truncate: 4.4.2 slice-ansi: 4.0.0 string-width: 4.2.3 @@ -9182,34 +9828,44 @@ packages: /through2@2.0.5: resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} dependencies: - readable-stream: 2.3.7 + readable-stream: 2.3.8 xtend: 4.0.2 dev: true /through2@4.0.2: resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} dependencies: - readable-stream: 3.6.0 + readable-stream: 3.6.2 dev: true /through@2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} dev: true - /tinybench@2.3.1: - resolution: {integrity: sha512-hGYWYBMPr7p4g5IarQE7XhlyWveh1EKhy4wUBS1LrHXCKYgvz+4/jCqgmJqZxxldesn05vccrtME2RLLZNW7iA==} + /time-zone@1.0.0: + resolution: {integrity: sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==} + engines: {node: '>=4'} + dev: true + + /tinybench@2.4.0: + resolution: {integrity: sha512-iyziEiyFxX4kyxSp+MtY1oCH/lvjH3PxFN8PGCDeqcZWAJ/i+9y+nL85w99PxVzrIvew/GSkSbDYtiGVa85Afg==} dev: true - /tinypool@0.3.1: - resolution: {integrity: sha512-zLA1ZXlstbU2rlpA4CIeVaqvWq41MTWqLY3FfsAXgC8+f7Pk7zroaJQxDgxn1xNudKW6Kmj4808rPFShUlIRmQ==} + /tinypool@0.4.0: + resolution: {integrity: sha512-2ksntHOKf893wSAH4z/+JbPpi92esw8Gn9N2deXX+B0EO92hexAVI9GIZZPx7P5aYo5KULfeOSt3kMOmSOy6uA==} engines: {node: '>=14.0.0'} dev: true - /tinyspy@1.1.1: - resolution: {integrity: sha512-UVq5AXt/gQlti7oxoIg5oi/9r0WpF7DGEVwXgqWSMmyN16+e3tl5lIvTaOpJ3TAtu5xFzWccFRM4R5NaWHF+4g==} + /tinyspy@2.1.0: + resolution: {integrity: sha512-7eORpyqImoOvkQJCSkL0d0mB4NHHIFAy4b1u8PHdDa7SjGS2njzl6/lyGoZLm+eyYEtlUmFGE0rFj66SWxZgQQ==} engines: {node: '>=14.0.0'} dev: true + /titleize@3.0.0: + resolution: {integrity: sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==} + engines: {node: '>=12'} + dev: true + /tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} @@ -9218,7 +9874,7 @@ packages: dev: true /to-fast-properties@2.0.0: - resolution: {integrity: sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=} + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} engines: {node: '>=4'} dev: true @@ -9234,6 +9890,16 @@ packages: engines: {node: '>=0.6'} dev: true + /tough-cookie@4.1.2: + resolution: {integrity: sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==} + engines: {node: '>=6'} + dependencies: + psl: 1.9.0 + punycode: 2.1.1 + universalify: 0.2.0 + url-parse: 1.5.10 + dev: true + /tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} dev: true @@ -9245,6 +9911,13 @@ packages: punycode: 2.1.1 dev: true + /tr46@4.1.1: + resolution: {integrity: sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==} + engines: {node: '>=14'} + dependencies: + punycode: 2.3.0 + dev: true + /trim-newlines@3.0.1: resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} engines: {node: '>=8'} @@ -9287,16 +9960,6 @@ packages: typescript: 4.9.5 dev: true - /tsutils@3.21.0(typescript@5.0.4): - resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} - engines: {node: '>= 6'} - peerDependencies: - typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' - dependencies: - tslib: 1.14.1 - typescript: 5.0.4 - dev: true - /tsx@3.12.6: resolution: {integrity: sha512-q93WgS3lBdHlPgS0h1i+87Pt6n9K/qULIMNYZo07nSeu2z5QE2CellcAZfofVXBo2tQg9av2ZcRMQ2S2i5oadQ==} hasBin: true @@ -9309,7 +9972,7 @@ packages: dev: true /type-check@0.3.2: - resolution: {integrity: sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=} + resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} engines: {node: '>= 0.8.0'} dependencies: prelude-ls: 1.1.2 @@ -9357,8 +10020,8 @@ packages: engines: {node: '>=12.20'} dev: true - /type-fest@3.6.1: - resolution: {integrity: sha512-htXWckxlT6U4+ilVgweNliPqlsVSSucbxVexRYllyMVJDtf5rTjv6kF/s+qAd4QSL1BZcnJPEJavYBPQiWuZDA==} + /type-fest@3.9.0: + resolution: {integrity: sha512-hR8JP2e8UiH7SME5JZjsobBlEiatFoxpzCP+R3ZeCo7kAaG1jXQE5X/buLzogM6GJu8le9Y4OcfNuIQX0rZskA==} engines: {node: '>=14.16'} dev: true @@ -9378,12 +10041,6 @@ packages: hasBin: true dev: true - /typescript@5.0.4: - resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==} - engines: {node: '>=12.20'} - hasBin: true - dev: true - /typeson-registry@1.0.0-alpha.39: resolution: {integrity: sha512-NeGDEquhw+yfwNhguLPcZ9Oj0fzbADiX4R0WxvoY8nGhy98IbzQy1sezjoEFWOywOboj/DWehI+/aUlRVrJnnw==} engines: {node: '>=10.0.0'} @@ -9402,12 +10059,12 @@ packages: resolution: {integrity: sha512-fKnGuqmTBnIE+/KXSzCn4db8RTigUzw1AN0DmdU6hJovUTbYJKyqj+8Mt1c4VfRDnOVJnENmfYkIPZ946UrSAA==} dev: true - /ufo@1.0.1: - resolution: {integrity: sha512-boAm74ubXHY7KJQZLlXrtMz52qFvpsbOxDcZOnw/Wf+LS4Mmyu7JxmzD4tDLtUQtmZECypJ0FrCz4QIe6dvKRA==} + /ufo@1.1.1: + resolution: {integrity: sha512-MvlCc4GHrmZdAllBc0iUDowff36Q9Ndw/UzqmEKyrfSzokTd9ZCy1i+IIk5hrYKkjoYVQyNbrw7/F8XJ2rEwTg==} dev: true - /uglify-js@3.17.3: - resolution: {integrity: sha512-JmMFDME3iufZnBpyKL+uS78LRiC+mK55zWfM5f/pWBJfpOttXAqYfdDGRukYhJuyRinvPVAtUhvy7rlDybNtFg==} + /uglify-js@3.17.4: + resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} engines: {node: '>=0.8.0'} hasBin: true requiresBuild: true @@ -9462,6 +10119,11 @@ packages: engines: {node: '>= 4.0.0'} dev: true + /universalify@0.2.0: + resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} + engines: {node: '>= 4.0.0'} + dev: true + /universalify@2.0.0: resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} engines: {node: '>= 10.0.0'} @@ -9472,6 +10134,11 @@ packages: engines: {node: '>= 0.8'} dev: true + /untildify@4.0.0: + resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} + engines: {node: '>=8'} + dev: true + /update-browserslist-db@1.0.10(browserslist@4.21.5): resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==} hasBin: true @@ -9514,8 +10181,15 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dev: true + /url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + dev: true + /util-deprecate@1.0.2: - resolution: {integrity: sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=} + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} dev: true /utility-types@3.10.0: @@ -9538,22 +10212,20 @@ packages: /validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} dependencies: - spdx-correct: 3.1.1 + spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 dev: true - /vite-node@0.28.4(@types/node@18.15.11): - resolution: {integrity: sha512-KM0Q0uSG/xHHKOJvVHc5xDBabgt0l70y7/lWTR7Q0pR5/MrYxadT+y32cJOE65FfjGmJgxpVEEY+69btJgcXOQ==} - engines: {node: '>=v14.16.0'} + /vite-node@0.30.1(@types/node@18.15.11): + resolution: {integrity: sha512-vTikpU/J7e6LU/8iM3dzBo8ZhEiKZEKRznEMm+mJh95XhWaPrJQraT/QsT2NWmuEf+zgAoMe64PKT7hfZ1Njmg==} + engines: {node: '>=v14.18.0'} hasBin: true dependencies: cac: 6.7.14 debug: 4.3.4 - mlly: 1.1.0 + mlly: 1.2.0 pathe: 1.1.0 picocolors: 1.0.0 - source-map: 0.6.1 - source-map-support: 0.5.21 vite: 4.2.2(@types/node@18.15.11) transitivePeerDependencies: - '@types/node' @@ -9644,9 +10316,9 @@ packages: vite: 4.2.2(@types/node@18.15.11) dev: true - /vitest@0.28.4: - resolution: {integrity: sha512-sfWIy0AdlbyGRhunm+TLQEJrFH9XuRPdApfubsyLcDbCRrUX717BRQKInTgzEfyl2Ipi1HWoHB84Nqtcwxogcg==} - engines: {node: '>=v14.16.0'} + /vitest@0.30.1(jsdom@21.1.1): + resolution: {integrity: sha512-y35WTrSTlTxfMLttgQk4rHcaDkbHQwDP++SNwPb+7H8yb13Q3cu2EixrtHzF27iZ8v0XCciSsLg00RkPAzB/aA==} + engines: {node: '>=v14.18.0'} hasBin: true peerDependencies: '@edge-runtime/vm': '*' @@ -9654,6 +10326,9 @@ packages: '@vitest/ui': '*' happy-dom: '*' jsdom: '*' + playwright: '*' + safaridriver: '*' + webdriverio: '*' peerDependenciesMeta: '@edge-runtime/vm': optional: true @@ -9665,30 +10340,39 @@ packages: optional: true jsdom: optional: true + playwright: + optional: true + safaridriver: + optional: true + webdriverio: + optional: true dependencies: '@types/chai': 4.3.4 '@types/chai-subset': 1.3.3 '@types/node': 18.15.11 - '@vitest/expect': 0.28.4 - '@vitest/runner': 0.28.4 - '@vitest/spy': 0.28.4 - '@vitest/utils': 0.28.4 + '@vitest/expect': 0.30.1 + '@vitest/runner': 0.30.1 + '@vitest/snapshot': 0.30.1 + '@vitest/spy': 0.30.1 + '@vitest/utils': 0.30.1 acorn: 8.8.2 acorn-walk: 8.2.0 cac: 6.7.14 chai: 4.3.7 + concordance: 5.0.4 debug: 4.3.4 + jsdom: 21.1.1 local-pkg: 0.4.3 + magic-string: 0.30.0 pathe: 1.1.0 picocolors: 1.0.0 source-map: 0.6.1 std-env: 3.3.2 strip-literal: 1.0.1 - tinybench: 2.3.1 - tinypool: 0.3.1 - tinyspy: 1.1.1 + tinybench: 2.4.0 + tinypool: 0.4.0 vite: 4.2.2(@types/node@18.15.11) - vite-node: 0.28.4(@types/node@18.15.11) + vite-node: 0.30.1(@types/node@18.15.11) why-is-node-running: 2.2.2 transitivePeerDependencies: - less @@ -9699,8 +10383,8 @@ packages: - terser dev: true - /vm2@3.9.14: - resolution: {integrity: sha512-HgvPHYHeQy8+QhzlFryvSteA4uQLBCOub02mgqdR+0bN/akRZ48TGB1v0aCv7ksyc0HXx16AZtMHKS38alc6TA==} + /vm2@3.9.17: + resolution: {integrity: sha512-AqwtCnZ/ERcX+AVj9vUsphY56YANXxRuqMb7GsDtAr0m0PcQX3u0Aj3KWiXM0YAHy7i6JEeHrwOnwXbGYgRpAw==} engines: {node: '>=6.0'} hasBin: true dependencies: @@ -9708,6 +10392,13 @@ packages: acorn-walk: 8.2.0 dev: true + /w3c-xmlserializer@4.0.0: + resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==} + engines: {node: '>=14'} + dependencies: + xml-name-validator: 4.0.0 + dev: true + /wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} dependencies: @@ -9732,6 +10423,36 @@ packages: engines: {node: '>=10.4'} dev: true + /webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + dev: true + + /well-known-symbols@2.0.0: + resolution: {integrity: sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==} + engines: {node: '>=6'} + dev: true + + /whatwg-encoding@2.0.0: + resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} + engines: {node: '>=12'} + dependencies: + iconv-lite: 0.6.3 + dev: true + + /whatwg-mimetype@3.0.0: + resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} + engines: {node: '>=12'} + dev: true + + /whatwg-url@12.0.1: + resolution: {integrity: sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==} + engines: {node: '>=14'} + dependencies: + tr46: 4.1.1 + webidl-conversions: 7.0.0 + dev: true + /whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} dependencies: @@ -9865,12 +10586,25 @@ packages: typedarray-to-buffer: 3.1.5 dev: true - /write-file-atomic@4.0.2: - resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + /write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dependencies: imurmurhash: 0.1.4 - signal-exit: 3.0.7 + signal-exit: 4.0.1 + dev: true + + /ws@8.13.0: + resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true dev: true /xdg-basedir@5.1.0: @@ -9878,6 +10612,15 @@ packages: engines: {node: '>=12'} dev: true + /xml-name-validator@4.0.0: + resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} + engines: {node: '>=12'} + dev: true + + /xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + dev: true + /xregexp@2.0.0: resolution: {integrity: sha512-xl/50/Cf32VsGq/1R8jJE5ajH1yMCQkpmoS10QbFZWl2Oor4H0Me64Pu2yxvsRWK3m6soJbmGfzSR7BYmDcWAA==} dev: true diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml deleted file mode 100644 index 9c9be4ba..00000000 --- a/pnpm-workspace.yaml +++ /dev/null @@ -1,2 +0,0 @@ -packages: - - "packages/**" diff --git a/scripts/release.mjs b/release.mjs similarity index 100% rename from scripts/release.mjs rename to release.mjs diff --git a/rollup-solid-svg.ts b/rollup-solid-svg.ts new file mode 100644 index 00000000..e3da1071 --- /dev/null +++ b/rollup-solid-svg.ts @@ -0,0 +1,63 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import { readFile } from 'node:fs/promises'; +import type { TransformResult } from 'rollup'; +import type { Config } from 'svgo'; +import { optimize } from 'svgo'; +import type { Plugin } from 'vite'; +import solid from 'vite-plugin-solid'; + +/** svgo 配置 */ +const svgoConfig: Config = { + plugins: [ + 'preset-default', + { + name: 'addAttributesToSVGElement', + params: { + attribute: { + stroke: 'currentColor', + fill: 'currentColor', + 'stroke-width': '0', + }, + }, + }, + ], +}; + +const optimizeSvg = (content: string, path: string) => { + if (svgoConfig.datauri) throw new Error('禁止使用 datauri 选项'); + + const result = optimize(content, { ...svgoConfig, path }); + return result.data; +}; + +/** 将导入的 svg 转为 solidjs 组件 */ +export function solidSvg(): Plugin { + const solidPlugin = solid(); + + return { + name: 'solid-svg', + enforce: 'pre', + + async load(path) { + if (!path.endsWith('svg')) return null; + + let code = await readFile(path, { encoding: 'utf8' }); + const optimized = optimizeSvg(code, path); + code = optimized || code; + + return `export default (props = {}) => ${code + .replace(/([{}])/g, "{'$1'}") + .replace(//g, '{/* $1 */}') + .replace(/(?<=)/i, '{...props}>')}`; + }, + + transform(source, path) { + if (!path.endsWith('svg')) return null; + + return (solidPlugin.transform as any).bind(this)( + source, + `${path}.tsx`, + ) as TransformResult; + }, + }; +} diff --git a/packages/ui-component/rollup.config.ts b/rollup.config.ts similarity index 73% rename from packages/ui-component/rollup.config.ts rename to rollup.config.ts index 11c8a7bf..877b0a77 100644 --- a/packages/ui-component/rollup.config.ts +++ b/rollup.config.ts @@ -1,34 +1,60 @@ -/* eslint-disable import/no-relative-packages */ /* eslint-disable import/no-extraneous-dependencies */ import fs from 'fs'; import { resolve, dirname } from 'path'; import { fileURLToPath } from 'url'; -import { rollup } from 'rollup'; +import shell from 'shelljs'; import { nodeResolve } from '@rollup/plugin-node-resolve'; import commonjs from '@rollup/plugin-commonjs'; -import del from 'rollup-plugin-delete'; -import serve from 'rollup-plugin-serve'; import { babel } from '@rollup/plugin-babel'; import styles from 'rollup-plugin-styles'; +import solidPlugin from 'vite-plugin-solid'; import replace from '@rollup/plugin-replace'; import { watchExternal } from 'rollup-plugin-watch-external'; -import solid from 'vite-plugin-solid'; -// import SolidSvg from 'vite-plugin-solid-svg'; -import type { Plugin, OutputOptions, RollupOptions } from 'rollup'; +import type { Plugin, RollupOptions } from 'rollup'; import { createServer } from 'vite'; import { solidSvg } from './rollup-solid-svg'; -import { DEV_PORT } from './vite.config'; - -import pkg from '../../package.json' assert { type: 'json' }; -import resource from '../userscript/resource.json' assert { type: 'json' }; +import pkg from './package.json' assert { type: 'json' }; const __dirname = dirname(fileURLToPath(import.meta.url)); +const DEV_PORT = 2405; + const isDevMode = process.env.NODE_ENV === 'development'; +/** + * 脚本依赖库与对应的 cdn url + * 数组里的第一个 url 是生产模式下使用的,第二个是开发模式下使用的 + * 只有一个 url 表示不区分生产开发模式 + */ +const resourceList: Record = { + 'solid-js': [ + 'https://unpkg.com/solid-js@1.7.3/dist/solid.cjs', + 'https://unpkg.com/solid-js@1.7.3/dist/dev.cjs', + ], + 'solid-js/store': [ + 'https://unpkg.com/solid-js@1.7.3/store/dist/store.cjs', + 'https://unpkg.com/solid-js@1.7.3/store/dist/dev.cjs', + ], + 'solid-js/web': [ + 'https://unpkg.com/solid-js@1.7.3/web/dist/web.cjs', + 'https://unpkg.com/solid-js@1.7.3/web/dist/dev.cjs', + ], + panzoom: ['https://unpkg.com/panzoom@9.4.3/dist/panzoom.min.js'], + fflate: ['https://unpkg.com/fflate@0.7.4/umd/index.js'], + dmzj_style: ['https://userstyles.org/styles/chrome/119945.json'], +}; +const resource = { + prod: Object.fromEntries( + Object.entries(resourceList).map(([k, v]) => [k, v.at(1)]), + ), + dev: Object.fromEntries( + Object.entries(resourceList).map(([k, v]) => [k, v.at(-1)]), + ), +}; + export const meta = { name: pkg.name, namespace: pkg.name, @@ -99,7 +125,7 @@ const metaHeader = (() => { return ['// ==UserScript==', metaStr, '// ==/UserScript=='].join('\n'); })(); -const build = ( +export const buildOptions = ( fileName: string, watchFiles?: string[], ...plugins: Array @@ -129,6 +155,7 @@ const build = ( commonjs(), styles({ modules: true }), + solidSvg(), babel({ babelHelpers: 'runtime', extensions: ['.ts', '.tsx'], @@ -136,32 +163,8 @@ const build = ( presets: ['@babel/preset-env', '@babel/preset-typescript', 'solid'], plugins: ['@babel/plugin-transform-runtime'], }), - watchFiles && isDevMode && watchExternal({ entries: watchFiles }), - - // 打包第一个脚本时清空 dist 文件夹 - fileName === 'dev' && del({ targets: resolve(__dirname, 'dist/*') }), - - solidSvg({ - svgo: { - enabled: true, - svgoConfig: { - plugins: [ - 'preset-default', - { - name: 'addAttributesToSVGElement', - params: { - attribute: { - stroke: 'currentColor', - fill: 'currentColor', - 'stroke-width': '0', - }, - }, - }, - ], - }, - }, - }), + watchFiles && isDevMode && watchExternal({ entries: watchFiles }), ...plugins, ], output: { @@ -230,22 +233,50 @@ const build = ( }; }; +// 清空 dist 文件夹 +shell.rm('-rf', resolve(__dirname, 'dist/*')); + (async () => { if (!isDevMode) return; // 创建一个 dist 文件夹的文件服务器,用于在浏览器获取最新的脚本代码 - const server = await createServer({ publicDir: resolve(__dirname, 'dist') }); + const server = await createServer({ + publicDir: resolve(__dirname, 'dist'), + server: { + host: true, + port: DEV_PORT, + cors: false, + }, + plugins: [ + { + name: 'selfPlugin', + enforce: 'pre', + transform(code, id): null | string { + if (id.includes('node_modules')) return null; + let newCode = code; + // 将 vite 不支持的 rollup-plugin-styles 相关 css 导出代码删除 + newCode = newCode.replace(', { css as style }', ''); + newCode = newCode.replace(/\n.+?Style = style;\n/, ''); + return newCode; + }, + }, + solidSvg(), + solidPlugin(), + ], + }); // 开启组件的测试服务器 await server.listen(); server.printUrls(); })(); export default [ - build('dev'), - build('main'), + buildOptions('dev'), + buildOptions('main'), - ...fs.readdirSync('src/site').map((fileName) => build(`site/${fileName}`)), + ...fs + .readdirSync('src/site') + .map((fileName) => buildOptions(`site/${fileName}`)), - build('helper/import', ['dist/cache/main.js']), + buildOptions('helper/import', ['dist/cache/main.js']), - build('index', ['dist/**/*', '!dist/index.js']), + buildOptions('index', ['dist/**/*', '!dist/index.js']), ]; diff --git a/packages/ui-component/src/components/Fab/display.tsx b/src/components/Fab/display.tsx similarity index 100% rename from packages/ui-component/src/components/Fab/display.tsx rename to src/components/Fab/display.tsx diff --git a/packages/ui-component/src/components/Fab/index.module.css b/src/components/Fab/index.module.css similarity index 99% rename from packages/ui-component/src/components/Fab/index.module.css rename to src/components/Fab/index.module.css index d8240914..f9e932a5 100644 --- a/packages/ui-component/src/components/Fab/index.module.css +++ b/src/components/Fab/index.module.css @@ -1,6 +1,5 @@ .fabRoot { font-size: 1.1em; - transition: transform 200ms; &[data-show="false"] { @@ -75,7 +74,6 @@ /* 在进度条满后自动隐藏 */ &[aria-valuenow="1"] { opacity: 0; - transition: opacity 200ms 150ms; } } @@ -144,9 +142,7 @@ & > .speedDialItem { transform: unset; - opacity: unset; - transition-delay: var(--show-delay); } } diff --git a/packages/ui-component/src/components/Fab/index.tsx b/src/components/Fab/index.tsx similarity index 98% rename from packages/ui-component/src/components/Fab/index.tsx rename to src/components/Fab/index.tsx index 5eb82f20..d68b073f 100644 --- a/packages/ui-component/src/components/Fab/index.tsx +++ b/src/components/Fab/index.tsx @@ -7,12 +7,10 @@ import { createSignal, mergeProps, } from 'solid-js'; - import { throttle } from 'throttle-debounce'; import MdMenuBook from '@material-design-icons/svg/round/menu_book.svg'; import classes, { css as style } from './index.module.css'; -// import style from './index.module.css?inline'; export const FabStyle = style; diff --git a/packages/ui-component/src/components/IconButton/display.tsx b/src/components/IconButton/display.tsx similarity index 99% rename from packages/ui-component/src/components/IconButton/display.tsx rename to src/components/IconButton/display.tsx index a56611b2..83ccf5f4 100644 --- a/packages/ui-component/src/components/IconButton/display.tsx +++ b/src/components/IconButton/display.tsx @@ -1,7 +1,9 @@ /* * 用于测试时显示组件 */ + import MdQueue from '@material-design-icons/svg/round/queue.svg'; + import { IconButton } from '.'; export default function Display() { diff --git a/packages/ui-component/src/components/IconButton/index.module.css b/src/components/IconButton/index.module.css similarity index 98% rename from packages/ui-component/src/components/IconButton/index.module.css rename to src/components/IconButton/index.module.css index bf805e46..fcfb22e8 100644 --- a/packages/ui-component/src/components/IconButton/index.module.css +++ b/src/components/IconButton/index.module.css @@ -1,6 +1,5 @@ .iconButtonItem { position: relative; - display: flex; align-items: center; } @@ -32,7 +31,6 @@ &.enabled { color: var(--text_bg, #121212); - background-color: var(--text, white); &:focus, @@ -44,6 +42,8 @@ /* 默认悬浮框样式 */ .iconButtonPopper { + user-select: none; + position: absolute; top: 50%; transform: translateY(-50%); @@ -66,7 +66,6 @@ &::before { right: calc(100% + 0.5em); - border-right-color: var(--switch_bg, #6e6e6e); border-right-width: 0.5em; } @@ -77,7 +76,6 @@ &::before { left: calc(100% + 0.5em); - border-left-color: var(--switch_bg, #6e6e6e); border-left-width: 0.5em; } diff --git a/packages/ui-component/src/components/IconButton/index.tsx b/src/components/IconButton/index.tsx similarity index 97% rename from packages/ui-component/src/components/IconButton/index.tsx rename to src/components/IconButton/index.tsx index 1553d420..62f3baf9 100644 --- a/packages/ui-component/src/components/IconButton/index.tsx +++ b/src/components/IconButton/index.tsx @@ -1,7 +1,7 @@ import type { Component, JSX } from 'solid-js'; import { mergeProps } from 'solid-js'; + import classes, { css as style } from './index.module.css'; -// import style from './index.module.css?inline'; export const IconButtonStyle = style; diff --git a/packages/ui-component/src/components/Manga/components/ComicImg.module.css b/src/components/Manga/components/ComicImg.module.css similarity index 93% rename from packages/ui-component/src/components/Manga/components/ComicImg.module.css rename to src/components/Manga/components/ComicImg.module.css index 76dd9e3f..48b79b68 100644 --- a/packages/ui-component/src/components/Manga/components/ComicImg.module.css +++ b/src/components/Manga/components/ComicImg.module.css @@ -1,19 +1,7 @@ -/* .touchAreaRoot { - display: none !important; -} */ - -/* .img, -.touchAreaRoot { - width: 7em !important; - height: 7em !important; -} */ - .img { display: none; - max-width: 100%; height: 100%; - object-fit: contain; &[data-show] { @@ -51,14 +39,12 @@ &.disableZoom .img { height: unset; max-height: 100%; - object-fit: scale-down; } &.scrollMode { /* 隐藏滚动条但不影响滚动 */ scrollbar-width: none; - overflow: auto; flex-direction: column; justify-content: flex-start; @@ -114,7 +100,6 @@ &[data-is-end] { margin: 2em; - font-size: 3em; } @@ -125,13 +110,11 @@ & > .tip { position: absolute; - margin: auto; } &[data-show] { pointer-events: all; - opacity: 1; } diff --git a/packages/ui-component/src/components/Manga/components/ComicImg.tsx b/src/components/Manga/components/ComicImg.tsx similarity index 99% rename from packages/ui-component/src/components/Manga/components/ComicImg.tsx rename to src/components/Manga/components/ComicImg.tsx index 8d5c0aa9..2a3acc24 100644 --- a/packages/ui-component/src/components/Manga/components/ComicImg.tsx +++ b/src/components/Manga/components/ComicImg.tsx @@ -1,5 +1,6 @@ import type { Component } from 'solid-js'; import { createMemo } from 'solid-js'; + import { store } from '../hooks/useStore'; import { handleImgError, handleImgLoaded } from '../hooks/useStore/slice'; diff --git a/packages/ui-component/src/components/Manga/components/ComicImgFlow.tsx b/src/components/Manga/components/ComicImgFlow.tsx similarity index 100% rename from packages/ui-component/src/components/Manga/components/ComicImgFlow.tsx rename to src/components/Manga/components/ComicImgFlow.tsx index d14eb25c..276a030a 100644 --- a/packages/ui-component/src/components/Manga/components/ComicImgFlow.tsx +++ b/src/components/Manga/components/ComicImgFlow.tsx @@ -1,7 +1,7 @@ import type { Component } from 'solid-js'; import { Index, onMount } from 'solid-js'; -import { ComicImg } from './ComicImg'; +import { ComicImg } from './ComicImg'; import { setState, store } from '../hooks/useStore'; import { handleMangaFlowScroll, initPanzoom } from '../hooks/useStore/slice'; diff --git a/packages/ui-component/src/components/Manga/components/EndPage.tsx b/src/components/Manga/components/EndPage.tsx similarity index 99% rename from packages/ui-component/src/components/Manga/components/EndPage.tsx rename to src/components/Manga/components/EndPage.tsx index b074ad74..aeefd3f7 100644 --- a/packages/ui-component/src/components/Manga/components/EndPage.tsx +++ b/src/components/Manga/components/EndPage.tsx @@ -6,10 +6,11 @@ import { onCleanup, onMount, } from 'solid-js'; + import { setState, store } from '../hooks/useStore'; +import { turnPage } from '../hooks/useStore/slice'; import classes from '../index.module.css'; -import { turnPage } from '../hooks/useStore/slice'; let delayTypeTimer = 0; diff --git a/packages/ui-component/src/components/Manga/components/Scrollbar.module.css b/src/components/Manga/components/Scrollbar.module.css similarity index 86% rename from packages/ui-component/src/components/Manga/components/Scrollbar.module.css rename to src/components/Manga/components/Scrollbar.module.css index eceb9b12..1e4e2b89 100644 --- a/packages/ui-component/src/components/Manga/components/Scrollbar.module.css +++ b/src/components/Manga/components/Scrollbar.module.css @@ -19,7 +19,6 @@ & > div { pointer-events: none; - display: flex; flex-direction: column; flex-grow: 1; @@ -37,20 +36,11 @@ opacity: 0; background-color: var(--scrollbar_drag); border-radius: 1em; - - /** - * 使用 transform 来移动的化因为涉及到百分比的四舍五入, - * 会在长漫画的滚动结束后出现明显的抖动, - * 所以这里只能用 top 来控制 - */ - /* stylelint-disable-next-line plugin/no-low-performance-animation-properties */ - transition: top 150ms; } .scrollbarPage { - transform: scaleY(1); transform-origin: bottom; - + transform: scaleY(1); flex-grow: 1; /* stylelint-disable-next-line plugin/no-low-performance-animation-properties */ diff --git a/src/components/Manga/components/Scrollbar.tsx b/src/components/Manga/components/Scrollbar.tsx new file mode 100644 index 00000000..23c7d351 --- /dev/null +++ b/src/components/Manga/components/Scrollbar.tsx @@ -0,0 +1,83 @@ +import type { Component } from 'solid-js'; +import { createMemo, Show, For } from 'solid-js'; +import { store } from '../hooks/useStore'; +import { handleWheel } from '../hooks/useStore/slice'; +import { useDrag } from '../hooks/useDrag'; + +import classes from '../index.module.css'; + +/** 滚动条上用于显示对应图片加载情况的元素 */ +const ScrollbarPage: Component<{ index: number }> = (props) => ( +
    +); + +/** 滚动条 */ +export const Scrollbar: Component = () => { + /** 滚动条高度 */ + const height = createMemo(() => + store.scrollbar.dragHeight + ? `${store.scrollbar.dragHeight * 100}%` + : `${(1 / store.pageList.length) * 100}%`, + ); + + /** 滚动条位置高度 */ + const top = createMemo(() => + store.option.scrollMode + ? `${store.scrollbar.dragTop * 100}%` + : `${(1 / store.pageList.length) * 100 * store.activePageIndex}%`, + ); + + return ( +
    useDrag(e)} + class={classes.scrollbar} + classList={{ + [classes.hidden]: + !store.option.scrollbar.enabled && !store.showScrollbar, + }} + role="scrollbar" + aria-controls={classes.mangaFlow} + aria-valuenow={store.activePageIndex || -1} + tabIndex={-1} + onWheel={handleWheel} + > +
    +
    + {store.scrollbar.tipText} +
    +
    + + + + {([a, b]) => ( +
    + + {b ? : null} +
    + )} +
    +
    +
    + ); +}; diff --git a/packages/ui-component/src/components/Manga/components/Setting.module.css b/src/components/Manga/components/Setting.module.css similarity index 99% rename from packages/ui-component/src/components/Manga/components/Setting.module.css rename to src/components/Manga/components/Setting.module.css index 12ac0f34..d55970f7 100644 --- a/packages/ui-component/src/components/Manga/components/Setting.module.css +++ b/src/components/Manga/components/Setting.module.css @@ -1,7 +1,6 @@ /* 设置面板所在的悬浮框样式 */ .SettingPanelPopper { transform: none !important; - height: 0 !important; padding: 0 !important; } @@ -41,7 +40,6 @@ .SettingBlockSubtitle { margin-bottom: -0.3em; - font-size: 0.7em; color: var(--text_secondary); } @@ -50,7 +48,6 @@ display: flex; align-items: center; justify-content: space-between; - margin-top: 1em; } @@ -95,7 +92,6 @@ & .SettingsItemSwitchRound { transform: translateX(110%); - background: var(--secondary); } } diff --git a/packages/ui-component/src/components/Manga/components/SettingPanel.tsx b/src/components/Manga/components/SettingPanel.tsx similarity index 100% rename from packages/ui-component/src/components/Manga/components/SettingPanel.tsx rename to src/components/Manga/components/SettingPanel.tsx index 748c1d4e..a8b8ebc5 100644 --- a/packages/ui-component/src/components/Manga/components/SettingPanel.tsx +++ b/src/components/Manga/components/SettingPanel.tsx @@ -1,11 +1,11 @@ import type { Component } from 'solid-js'; import { For, createMemo } from 'solid-js'; -import { store } from '../hooks/useStore'; import { defaultSettingList } from '../defaultSettingList'; +import { store } from '../hooks/useStore'; +import { stopPropagation } from '../helper'; import classes from '../index.module.css'; -import { stopPropagation } from '../helper'; /** 菜单面板 */ export const SettingPanel: Component = () => { diff --git a/packages/ui-component/src/components/Manga/components/SettingsItem.tsx b/src/components/Manga/components/SettingsItem.tsx similarity index 100% rename from packages/ui-component/src/components/Manga/components/SettingsItem.tsx rename to src/components/Manga/components/SettingsItem.tsx diff --git a/packages/ui-component/src/components/Manga/components/SettingsItemSwitch.tsx b/src/components/Manga/components/SettingsItemSwitch.tsx similarity index 99% rename from packages/ui-component/src/components/Manga/components/SettingsItemSwitch.tsx rename to src/components/Manga/components/SettingsItemSwitch.tsx index a5d56a62..262f6577 100644 --- a/packages/ui-component/src/components/Manga/components/SettingsItemSwitch.tsx +++ b/src/components/Manga/components/SettingsItemSwitch.tsx @@ -1,4 +1,5 @@ import type { Component } from 'solid-js'; + import { SettingsItem } from './SettingsItem'; import classes from '../index.module.css'; diff --git a/packages/ui-component/src/components/Manga/components/Toolbar.module.css b/src/components/Manga/components/Toolbar.module.css similarity index 100% rename from packages/ui-component/src/components/Manga/components/Toolbar.module.css rename to src/components/Manga/components/Toolbar.module.css diff --git a/packages/ui-component/src/components/Manga/components/Toolbar.tsx b/src/components/Manga/components/Toolbar.tsx similarity index 100% rename from packages/ui-component/src/components/Manga/components/Toolbar.tsx rename to src/components/Manga/components/Toolbar.tsx index 07bdb9d4..f60743b1 100644 --- a/packages/ui-component/src/components/Manga/components/Toolbar.tsx +++ b/src/components/Manga/components/Toolbar.tsx @@ -1,9 +1,9 @@ import type { Component } from 'solid-js'; import { For } from 'solid-js'; -import { useHover } from '../hooks/useHover'; -import { store } from '../hooks/useStore'; import { defaultButtonList } from '../defaultButtonList'; +import { useHover } from '../hooks/useHover'; +import { store } from '../hooks/useStore'; import classes from '../index.module.css'; diff --git a/packages/ui-component/src/components/Manga/components/TouchArea.module.css b/src/components/Manga/components/TouchArea.module.css similarity index 100% rename from packages/ui-component/src/components/Manga/components/TouchArea.module.css rename to src/components/Manga/components/TouchArea.module.css diff --git a/packages/ui-component/src/components/Manga/components/TouchArea.tsx b/src/components/Manga/components/TouchArea.tsx similarity index 99% rename from packages/ui-component/src/components/Manga/components/TouchArea.tsx rename to src/components/Manga/components/TouchArea.tsx index a5f230d6..de931abc 100644 --- a/packages/ui-component/src/components/Manga/components/TouchArea.tsx +++ b/src/components/Manga/components/TouchArea.tsx @@ -1,10 +1,11 @@ import type { Component } from 'solid-js'; import { on, createEffect, createSignal } from 'solid-js'; + import { setState, store } from '../hooks/useStore'; import { useDoubleClick } from '../hooks/useDoubleClick'; +import { turnPage } from '../hooks/useStore/slice'; import classes from '../index.module.css'; -import { turnPage } from '../hooks/useStore/slice'; export const TouchArea: Component = () => { /** 处理双击缩放 */ diff --git a/packages/ui-component/src/components/Manga/defaultButtonList.tsx b/src/components/Manga/defaultButtonList.tsx similarity index 88% rename from packages/ui-component/src/components/Manga/defaultButtonList.tsx rename to src/components/Manga/defaultButtonList.tsx index 8bf8baff..ca02a959 100644 --- a/packages/ui-component/src/components/Manga/defaultButtonList.tsx +++ b/src/components/Manga/defaultButtonList.tsx @@ -15,6 +15,8 @@ import classes from './index.module.css'; import { activeImgIndex, handleMangaFlowScroll, + nowFillIndex, + setOption, switchFillEffect, updatePageData, } from './hooks/useStore/slice'; @@ -38,7 +40,9 @@ export const defaultButtonList: ToolbarButtonList = [ const isOnePageMode = store.option.onePageMode; const handleClick = () => { setState((state) => { - state.option.onePageMode = !state.option.onePageMode; + setOption((draftOption) => { + draftOption.onePageMode = !draftOption.onePageMode; + }); updatePageData(state); state.activePageIndex = state.option.onePageMode ? activeImgIndex() @@ -60,8 +64,10 @@ export const defaultButtonList: ToolbarButtonList = [ () => { const handleClick = () => { setState((state) => { - state.option.scrollMode = !state.option.scrollMode; - state.option.onePageMode = state.option.scrollMode; + setOption((draftOption) => { + draftOption.scrollMode = !draftOption.scrollMode; + draftOption.onePageMode = draftOption.scrollMode; + }); updatePageData(state); handleMangaFlowScroll(); }); @@ -82,7 +88,7 @@ export const defaultButtonList: ToolbarButtonList = [ return (