From d274cbade1730d62c100d2ec15ff291dbb434d46 Mon Sep 17 00:00:00 2001 From: hymbz Date: Fri, 26 May 2023 15:03:54 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20:recycle:=20=E5=AE=9E=E7=8E=B0=20to?= =?UTF-8?q?ast?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .stylelintrc.js | 5 +- docs/Dev.md | 1 + index.html | 1 + package.json | 1 - pnpm-lock.yaml | 3 - rollup.config.ts | 16 ++- .../Manga/components/ComicImg.module.css | 1 + src/components/Toast/ToastItem.tsx | 91 +++++++++++++ src/components/Toast/Toaster.tsx | 29 ++++ src/components/Toast/display.tsx | 50 +++++++ src/components/Toast/helper.tsx | 21 +++ src/components/Toast/index.module.css | 126 ++++++++++++++++++ src/components/Toast/index.ts | 22 +++ src/components/Toast/toast.tsx | 40 ++++++ src/components/useComponents/Fab.tsx | 2 +- src/components/useComponents/Manga.tsx | 5 +- src/components/useComponents/Toast.tsx | 70 +++------- src/components/useComponents/helper.ts | 12 ++ src/components/useComponents/toast.module.css | 73 ---------- src/helper/import.ts | 18 ++- src/helper/index.ts | 21 +-- src/helper/useInit.tsx | 87 +++++++----- src/site/ehentai.tsx | 2 +- src/site/jm.tsx | 2 +- 24 files changed, 498 insertions(+), 201 deletions(-) create mode 100644 src/components/Toast/ToastItem.tsx create mode 100644 src/components/Toast/Toaster.tsx create mode 100644 src/components/Toast/display.tsx create mode 100644 src/components/Toast/helper.tsx create mode 100644 src/components/Toast/index.module.css create mode 100644 src/components/Toast/index.ts create mode 100644 src/components/Toast/toast.tsx create mode 100644 src/components/useComponents/helper.ts delete mode 100644 src/components/useComponents/toast.module.css diff --git a/.stylelintrc.js b/.stylelintrc.js index 8d00b694..ae96662b 100644 --- a/.stylelintrc.js +++ b/.stylelintrc.js @@ -16,8 +16,11 @@ module.exports = { // 允许 css 变量使用任意命名方式 'custom-property-pattern': null, - // 允许任意类型的类名命名方式 + // 允许任意类型的命名方式 'selector-class-pattern': null, + 'keyframes-name-pattern': null, + // 允许重复的 css 动画帧 + 'keyframe-block-no-duplicate-selectors': null, // 防止使用低性能的动画和过度属性 'plugin/no-low-performance-animation-properties': true, diff --git a/docs/Dev.md b/docs/Dev.md index 2fece392..4a3337ba 100644 --- a/docs/Dev.md +++ b/docs/Dev.md @@ -2,6 +2,7 @@ - 测试平板上的使用 - 300 自动签到功能在首次签到成功时报错 +- dmzj 隐藏漫画增加上下话切换 卷轴模式下图片的宽度应该要能简单调整,加设置项太麻烦,应该直接使用缩放功能来实现。目前已经可以在保持缩放的状态下滚动了,但现在使用的缩放库有几个问题 1. 没办法在缩小后保持图片居中 diff --git a/index.html b/index.html index ed162e93..5b505be9 100644 --- a/index.html +++ b/index.html @@ -14,6 +14,7 @@ + )); - } - - solidToast(message, opts); }; -toast.success = (message: string, opts?: ToastOptions) => - toast(message, { - icon: ( -
- -
- ), - ...opts, - }); -toast.warn = (message: string, opts?: ToastOptions) => - toast(message, { - icon: ( -
- -
- ), - ...opts, - }); -toast.error = (message: string, opts?: ToastOptions) => - toast(message, { - icon: ( -
- -
- ), - ...opts, - }); +export const toast = new Proxy(_toast, { + get(target, propKey: keyof typeof _toast) { + init(); + return target[propKey]; + }, + apply(target, propKey: keyof typeof _toast, args) { + init(); + const fn: any = propKey ? target[propKey] : target; + return fn(...args) as unknown; + }, +}); diff --git a/src/components/useComponents/helper.ts b/src/components/useComponents/helper.ts new file mode 100644 index 00000000..66407d63 --- /dev/null +++ b/src/components/useComponents/helper.ts @@ -0,0 +1,12 @@ +import type { JSX } from 'solid-js'; +import { render } from 'solid-js/web'; + +/** 挂载 solid-js 组件 */ +export const mountComponents = (id: string, fc: () => JSX.Element) => { + const dom = document.createElement('div'); + dom.id = id; + document.body.appendChild(dom); + const shadowDom = dom.attachShadow({ mode: 'open' }); + render(fc, shadowDom); + return dom; +}; diff --git a/src/components/useComponents/toast.module.css b/src/components/useComponents/toast.module.css deleted file mode 100644 index c758bc25..00000000 --- a/src/components/useComponents/toast.module.css +++ /dev/null @@ -1,73 +0,0 @@ -.toast { - will-change: transform; - - overflow: hidden; - display: flex; - align-items: center; - - padding: 0.7em 1em; - - color: #f3f4f6; - - background: #1f2937; - border-radius: 0.5em; - box-shadow: rgb(0 0 0 / 10%) 0 3px 10px, rgb(0 0 0 / 5%) 0 3px 3px; - - &[data-visible="true"] { - animation: enter 0.2s ease-out; - } - - &[data-visible="false"] { - animation: leave 0.15s ease-in forwards; - } -} - -button { - cursor: pointer; - - margin-left: 1em; - padding: 0; - - color: currentcolor; - - background-color: transparent; - border: none; - - &:hover { - color: #e5e7ebcc; - } -} - -.progress { - position: absolute; - bottom: 0; - left: 0; - - height: 2px; - - background-color: #41bcf4; -} - -@keyframes enter { - 0% { - transform: scale(0.9); - opacity: 0; - } - - 100% { - transform: scale(1); - opacity: 1; - } -} - -@keyframes leave { - 0% { - transform: scale(1); - opacity: 1; - } - - 100% { - transform: scale(0.9); - opacity: 0; - } -} diff --git a/src/helper/import.ts b/src/helper/import.ts index a25b230e..41f0fc27 100644 --- a/src/helper/import.ts +++ b/src/helper/import.ts @@ -1,11 +1,16 @@ declare const isDevMode: boolean; +const GMRe = /^GM/; +const gmApiList = Object.keys(window).filter((name) => GMRe.test(name)); +const gmApiMap = Object.fromEntries( + gmApiList.map((name) => [name, window[name]]), +); + unsafeWindow.crsLib = { // 有些 cjs 模块会检查这个,所以在这里声明下 process: { env: { NODE_ENV: process.env.NODE_ENV } }, - // 把 GM 相关函数放进去以便其中使用 - GM_xmlhttpRequest, - GM, + // 把 GM API 放进去以便使用 + ...gmApiMap, }; /** @@ -18,11 +23,11 @@ const selfImportSync = (name: string) => { // 通过提供 cjs 环境的变量来兼容 umd 模块加载器 // 将模块导出变量放到 crsLib 对象里,防止污染全局作用域和网站自身的模块产生冲突 - return GM_addElement('script', { + GM_addElement('script', { textContent: ` window.crsLib['${name}'] = {}; ${isDevMode ? `console.time('导入 ${name}');` : ''} - (function (process, require, exports, module, GM, GM_xmlhttpRequest) { + (function (process, require, exports, module, ${gmApiList.join(', ')}) { ${code} })( window.crsLib.process, @@ -36,8 +41,7 @@ const selfImportSync = (name: string) => { return window.crsLib['${name}']; }, }, - window.crsLib.GM, - window.crsLib.GM_xmlhttpRequest, + ${gmApiList.map((apiName) => `window.crsLib.${apiName}`).join(', ')} ); ${isDevMode ? `console.timeEnd('导入 ${name}');` : ''} `, diff --git a/src/helper/index.ts b/src/helper/index.ts index 46754623..955ef7e7 100644 --- a/src/helper/index.ts +++ b/src/helper/index.ts @@ -1,5 +1,4 @@ -import type { JSX } from 'solid-js'; -import { render } from 'solid-js/web'; +import { toast } from '../components/useComponents/Toast'; export type AsyncReturnType Promise> = T extends (...args: any) => Promise ? R : any; @@ -43,16 +42,6 @@ export const insertNode = ( node.insertBefore(frag, referenceNode); }; -/** 挂载 solid-js 组件 */ -export const mountComponents = (id: string, fc: () => JSX.Element) => { - const dom = document.createElement('div'); - dom.id = id; - document.body.appendChild(dom); - const shadowDom = dom.attachShadow({ mode: 'open' }); - render(fc, shadowDom); - return dom; -}; - /** 返回 Dom 的点击函数 */ export const querySelectorClick = (selector: string) => { const dom = querySelector(selector); @@ -158,6 +147,7 @@ export const request = async ( url: string, details?: Partial> & { errorText?: string; + noTip?: true; }, errorNum = 0, ): Promise> => { @@ -172,11 +162,8 @@ export const request = async ( if (res.status !== 200) throw new Error(errorText); return res; } catch (error) { - if (errorNum > 3) { - if (errorText) { - const { useToast } = require('../main'); - useToast().error(errorText); - } + if (errorNum >= 3) { + if (errorText && !details?.noTip) toast.error(errorText); throw new Error(errorText); } console.error(errorText, error); diff --git a/src/helper/useInit.tsx b/src/helper/useInit.tsx index eedd0891..2a399377 100644 --- a/src/helper/useInit.tsx +++ b/src/helper/useInit.tsx @@ -1,8 +1,10 @@ +import { For } from 'solid-js'; import { useManga } from '../components/useComponents/Manga'; import { useFab } from '../components/useComponents/Fab'; import { toast } from '../components/useComponents/Toast'; import { useSiteOptions } from './useSiteOptions'; import { useSpeedDial } from './useSpeedDial'; +import { request } from '.'; /** * 对所有支持站点页面的初始化操作的封装 @@ -32,43 +34,56 @@ export const useInit = async >( // 检查脚本的版本变化,提示用户 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); + const res = await request( + `https://cdn.jsdelivr.net/gh/hymbz/ComicReadScriptTest@${GM.info.script.version}/docs/LatestChange.md`, + { errorText: '' }, + ); + toast( + () => ( + <> +

🥳 ComicRead 已更新到 v{GM.info.script.version}

+
+ + {(mdText) => { + switch (mdText[0]) { + case '#': + return

{mdText.replace('### ', '')}

; + case '*': + return ( +
    + + {(item) =>
  • {item}
  • } +
    +
+ ); + default: + return null; + } + }} +
+
+ + ), + { + id: 'Version Tip', + duration: Infinity, + // 手动点击关掉通知后才不会再次弹出 + onDismiss: () => GM.setValue('Version', GM.info.script.version), + }, + ); })(); + + // 监听储存的版本数据的变动,如果和当前版本一致就关掉弹窗 + // 防止在更新版本后一次性打开多个页面,不得不一个一个关过去 + const listenerId = await GM.addValueChangeListener( + 'Version', + async (_, __, newVersion) => { + if (newVersion !== GM.info.script.version) return; + toast.dismiss('Version Tip'); + await GM.removeValueChangeListener(listenerId); + }, + ); } let menuId: number; @@ -115,7 +130,7 @@ export const useInit = async >( const showComic = async (show: boolean = options.autoShow) => { if (loading) { toast.warn('加载图片中,请稍候', { - unmountDelay: 1500, + duration: 1500, id: '加载图片中,请稍候', }); return; diff --git a/src/site/ehentai.tsx b/src/site/ehentai.tsx index 47b5d96a..12ff63ff 100644 --- a/src/site/ehentai.tsx +++ b/src/site/ehentai.tsx @@ -146,7 +146,7 @@ declare const selected_link: HTMLElement; `https://nhentai.net/api/galleries/search?query=${encodeURI( titleDom.innerText, )}`, - { errorText: '' }, + { errorText: 'nhentai 匹配出错', noTip: true }, ); } catch (_) { newTagLine.innerHTML = ` diff --git a/src/site/jm.tsx b/src/site/jm.tsx index 2e501420..9dff4527 100644 --- a/src/site/jm.tsx +++ b/src/site/jm.tsx @@ -15,7 +15,7 @@ import { while (!unsafeWindow?.onImageLoaded) { if (document.readyState === 'complete') { - toast.error('无法获取图片', { duration: 60000 }); + toast.error('无法获取图片', { duration: Infinity }); return; } // eslint-disable-next-line no-await-in-loop