diff --git a/src/apis/index.js b/src/apis/index.js index 3142a3a..5dc43a7 100644 --- a/src/apis/index.js +++ b/src/apis/index.js @@ -1,6 +1,7 @@ import queryString from "query-string"; import { fetchPolyfill } from "../libs/fetch"; import { + GLOBAL_KEY, OPT_TRANS_GOOGLE, OPT_TRANS_MICROSOFT, OPT_TRANS_OPENAI, @@ -10,8 +11,9 @@ import { PROMPT_PLACE_TO, KV_SALT_SYNC, } from "../config"; -import { getSetting, detectLang } from "../libs"; +import { detectLang } from "../libs/browser"; import { sha256 } from "../libs/utils"; +import { checkRules } from "../libs/rules"; /** * 同步数据 @@ -31,6 +33,20 @@ export const apiSyncData = async (url, key, data, isBg = false) => isBg, }); +/** + * 下载订阅规则 + * @param {*} url + * @param {*} isBg + * @returns + */ +export const apiFetchRules = async (url, isBg = false) => { + const res = await fetchPolyfill(url, { isBg }); + const rules = checkRules(res).filter( + (rule) => rule.pattern.replaceAll(GLOBAL_KEY, "") !== "" + ); + return rules; +}; + /** * 谷歌翻译 * @param {*} text @@ -38,7 +54,8 @@ export const apiSyncData = async (url, key, data, isBg = false) => * @param {*} from * @returns */ -const apiGoogleTranslate = async (translator, text, to, from) => { +const apiGoogleTranslate = async (translator, text, to, from, setting) => { + const { googleUrl } = setting; const params = { client: "gtx", dt: "t", @@ -48,7 +65,6 @@ const apiGoogleTranslate = async (translator, text, to, from) => { tl: to, q: text, }; - const { googleUrl } = await getSetting(); const input = `${googleUrl}?${queryString.stringify(params)}`; return fetchPolyfill(input, { headers: { @@ -93,9 +109,8 @@ const apiMicrosoftTranslate = (translator, text, to, from) => { * @param {*} from * @returns */ -const apiOpenaiTranslate = async (translator, text, to, from) => { - const { openaiUrl, openaiKey, openaiModel, openaiPrompt } = - await getSetting(); +const apiOpenaiTranslate = async (translator, text, to, from, setting) => { + const { openaiUrl, openaiKey, openaiModel, openaiPrompt } = setting; let prompt = openaiPrompt .replaceAll(PROMPT_PLACE_FROM, from) .replaceAll(PROMPT_PLACE_TO, to); @@ -131,7 +146,13 @@ const apiOpenaiTranslate = async (translator, text, to, from) => { * @param {*} param0 * @returns */ -export const apiTranslate = async ({ translator, q, fromLang, toLang }) => { +export const apiTranslate = async ({ + translator, + q, + fromLang, + toLang, + setting, +}) => { let trText = ""; let isSame = false; @@ -139,7 +160,7 @@ export const apiTranslate = async ({ translator, q, fromLang, toLang }) => { let to = OPT_LANGS_SPECIAL?.[translator]?.get(toLang) ?? toLang; if (translator === OPT_TRANS_GOOGLE) { - const res = await apiGoogleTranslate(translator, q, to, from); + const res = await apiGoogleTranslate(translator, q, to, from, setting); trText = res.sentences.map((item) => item.trans).join(" "); isSame = to === res.src; } else if (translator === OPT_TRANS_MICROSOFT) { @@ -147,9 +168,11 @@ export const apiTranslate = async ({ translator, q, fromLang, toLang }) => { trText = res[0].translations[0].text; isSame = to === res[0].detectedLanguage.language; } else if (translator === OPT_TRANS_OPENAI) { - const res = await apiOpenaiTranslate(translator, q, to, from); + const res = await apiOpenaiTranslate(translator, q, to, from, setting); trText = res?.choices?.[0].message.content; - isSame = (await detectLang(q)) === (await detectLang(trText)); + const sLang = await detectLang(q); + const tLang = await detectLang(trText); + isSame = q === trText || (sLang && tLang && sLang === tLang); } return [trText, isSame]; diff --git a/src/background.js b/src/background.js index 594c7c4..413950b 100644 --- a/src/background.js +++ b/src/background.js @@ -7,35 +7,19 @@ import { MSG_TRANS_TOGGLE_STYLE, CMD_TOGGLE_TRANSLATE, CMD_TOGGLE_STYLE, - DEFAULT_SETTING, - DEFAULT_RULES, - DEFAULT_SYNC, - STOKEY_SETTING, - STOKEY_RULES, - STOKEY_SYNC, - CACHE_NAME, - STOKEY_RULESCACHE_PREFIX, - BUILTIN_RULES, } from "./config"; -import storage from "./libs/storage"; -import { getSetting } from "./libs"; +import { getSettingWithDefault, tryInitDefaultData } from "./libs/storage"; import { trySyncAll } from "./libs/sync"; import { fetchData, fetchPool } from "./libs/fetch"; import { sendTabMsg } from "./libs/msg"; -import { trySyncAllSubRules } from "./libs/rules"; +import { trySyncAllSubRules } from "./libs/subRules"; +import { tryClearCaches } from "./libs"; /** * 插件安装 */ browser.runtime.onInstalled.addListener(() => { - console.log("KISS Translator onInstalled"); - storage.trySetObj(STOKEY_SETTING, DEFAULT_SETTING); - storage.trySetObj(STOKEY_RULES, DEFAULT_RULES); - storage.trySetObj(STOKEY_SYNC, DEFAULT_SYNC); - storage.trySetObj( - `${STOKEY_RULESCACHE_PREFIX}${process.env.REACT_APP_RULESURL}`, - BUILTIN_RULES - ); + tryInitDefaultData(); }); /** @@ -48,13 +32,9 @@ browser.runtime.onStartup.addListener(async () => { await trySyncAll(true); // 清除缓存 - const setting = await getSetting(); + const setting = await getSettingWithDefault(); if (setting.clearCache) { - try { - caches.delete(CACHE_NAME); - } catch (err) { - console.log("[clean caches]", err.message); - } + tryClearCaches(); } // 同步订阅规则 diff --git a/src/config/app.js b/src/config/app.js new file mode 100644 index 0000000..7122385 --- /dev/null +++ b/src/config/app.js @@ -0,0 +1,4 @@ +export const APP_NAME = process.env.REACT_APP_NAME.trim() + .split(/\s+/) + .join("-"); +export const APP_LCNAME = APP_NAME.toLowerCase(); diff --git a/src/config/index.js b/src/config/index.js index 1938472..023da41 100644 --- a/src/config/index.js +++ b/src/config/index.js @@ -5,12 +5,9 @@ import { DEFAULT_RULE, BUILTIN_RULES, } from "./rules"; +import { APP_NAME, APP_LCNAME } from "./app"; export { I18N, UI_LANGS } from "./i18n"; -export { GLOBAL_KEY, SHADOW_KEY, DEFAULT_RULE, BUILTIN_RULES }; - -const APP_NAME = process.env.REACT_APP_NAME.trim().split(/\s+/).join("-"); - -export const APP_LCNAME = APP_NAME.toLowerCase(); +export { GLOBAL_KEY, SHADOW_KEY, DEFAULT_RULE, BUILTIN_RULES, APP_LCNAME }; export const STOKEY_MSAUTH = `${APP_NAME}_msauth`; export const STOKEY_SETTING = `${APP_NAME}_setting`; @@ -163,6 +160,7 @@ export const DEFAULT_SUBRULES_LIST = [ }, { url: "https://fishjar.github.io/kiss-translator/kiss-translator-rules.json", + selected: false, }, ]; diff --git a/src/content.js b/src/content.js index e791f81..509fdb8 100644 --- a/src/content.js +++ b/src/content.js @@ -5,17 +5,18 @@ import { MSG_TRANS_GETRULE, MSG_TRANS_PUTRULE, } from "./config"; -import { getSetting, getRules, matchRule } from "./libs"; +import { getSettingWithDefault, getRulesWithDefault } from "./libs/storage"; import { Translator } from "./libs/translator"; import { isIframe } from "./libs/iframe"; +import { matchRule } from "./libs/rules"; /** * 入口函数 */ const init = async () => { const href = isIframe ? document.referrer : document.location.href; - const setting = await getSetting(); - const rules = await getRules(); + const setting = await getSettingWithDefault(); + const rules = await getRulesWithDefault(); const rule = await matchRule(rules, href, setting); const translator = new Translator(rule, setting); diff --git a/src/hooks/Alert.js b/src/hooks/Alert.js index 56567cc..12e0684 100644 --- a/src/hooks/Alert.js +++ b/src/hooks/Alert.js @@ -20,11 +20,6 @@ export function AlertProvider({ children }) { const [severity, setSeverity] = useState("info"); const [message, setMessage] = useState(""); - const error = (msg) => showAlert(msg, "error"); - const warning = (msg) => showAlert(msg, "warning"); - const info = (msg) => showAlert(msg, "info"); - const success = (msg) => showAlert(msg, "success"); - const showAlert = (msg, type) => { setOpen(true); setMessage(msg); @@ -38,6 +33,11 @@ export function AlertProvider({ children }) { setOpen(false); }; + const error = (msg) => showAlert(msg, "error"); + const warning = (msg) => showAlert(msg, "warning"); + const info = (msg) => showAlert(msg, "info"); + const success = (msg) => showAlert(msg, "success"); + return ( {children} diff --git a/src/hooks/ColorMode.js b/src/hooks/ColorMode.js index dc7c714..1dc90f1 100644 --- a/src/hooks/ColorMode.js +++ b/src/hooks/ColorMode.js @@ -1,22 +1,19 @@ -import { useSetting, useSettingUpdate } from "./Setting"; +import { useCallback } from "react"; +import { useSetting } from "./Setting"; /** * 深色模式hook * @returns */ export function useDarkMode() { - const setting = useSetting(); - return !!setting?.darkMode; -} + const { + setting: { darkMode }, + updateSetting, + } = useSetting(); -/** - * 切换深色模式 - * @returns - */ -export function useDarkModeSwitch() { - const darkMode = useDarkMode(); - const updateSetting = useSettingUpdate(); - return async () => { + const toggleDarkMode = useCallback(async () => { await updateSetting({ darkMode: !darkMode }); - }; + }, [darkMode]); + + return { darkMode, toggleDarkMode }; } diff --git a/src/hooks/I18n.js b/src/hooks/I18n.js index 0b62034..f367fd1 100644 --- a/src/hooks/I18n.js +++ b/src/hooks/I18n.js @@ -7,7 +7,9 @@ import { useFetch } from "./Fetch"; * @returns */ export const useI18n = () => { - const { uiLang } = useSetting() ?? {}; + const { + setting: { uiLang }, + } = useSetting(); return (key, defaultText = "") => I18N?.[key]?.[uiLang] ?? defaultText; }; diff --git a/src/hooks/Rules.js b/src/hooks/Rules.js index 9ca692c..5396518 100644 --- a/src/hooks/Rules.js +++ b/src/hooks/Rules.js @@ -1,107 +1,125 @@ -import { STOKEY_RULES, DEFAULT_SUBRULES_LIST } from "../config"; -import storage from "../libs/storage"; -import { useStorages } from "./Storage"; +import { STOKEY_RULES, DEFAULT_RULES } from "../config"; +import { useStorage } from "./Storage"; import { trySyncRules } from "../libs/sync"; import { useSync } from "./Sync"; -import { useSetting, useSettingUpdate } from "./Setting"; import { checkRules } from "../libs/rules"; +import { useCallback } from "react"; /** - * 匹配规则增删改查 hook + * 规则 hook * @returns */ export function useRules() { - const storages = useStorages(); - const list = storages?.[STOKEY_RULES] || []; - const sync = useSync(); + const { data: list, save } = useStorage(STOKEY_RULES, DEFAULT_RULES); + const { + sync: { rulesUpdateAt }, + updateSync, + } = useSync(); - const update = async (rules) => { - const updateAt = sync.opt?.rulesUpdateAt ? Date.now() : 0; - await storage.setObj(STOKEY_RULES, rules); - await sync.update({ rulesUpdateAt: updateAt }); - trySyncRules(); - }; + const updateRules = useCallback( + async (rules) => { + const updateAt = rulesUpdateAt ? Date.now() : 0; + await save(rules); + await updateSync({ rulesUpdateAt: updateAt }); + trySyncRules(); + }, + [rulesUpdateAt] + ); - const add = async (rule) => { - const rules = [...list]; - if (rule.pattern === "*") { - return; - } - if (rules.map((item) => item.pattern).includes(rule.pattern)) { - return; - } - rules.unshift(rule); - await update(rules); - }; - - const del = async (pattern) => { - let rules = [...list]; - if (pattern === "*") { - return; - } - rules = rules.filter((item) => item.pattern !== pattern); - await update(rules); - }; - - const put = async (pattern, obj) => { - const rules = [...list]; - if (pattern === "*") { - obj.pattern = "*"; - } - const rule = rules.find((r) => r.pattern === pattern); - rule && Object.assign(rule, obj); - await update(rules); - }; - - const merge = async (newRules) => { - const rules = [...list]; - newRules = checkRules(newRules); - newRules.forEach((newRule) => { - const rule = rules.find((oldRule) => oldRule.pattern === newRule.pattern); - if (rule) { - Object.assign(rule, newRule); - } else { - rules.unshift(newRule); + const add = useCallback( + async (rule) => { + const rules = [...list]; + if (rule.pattern === "*") { + return; } - }); - await update(rules); - }; + if (rules.map((item) => item.pattern).includes(rule.pattern)) { + return; + } + rules.unshift(rule); + await updateRules(rules); + }, + [list, updateRules] + ); + + const del = useCallback( + async (pattern) => { + let rules = [...list]; + if (pattern === "*") { + return; + } + rules = rules.filter((item) => item.pattern !== pattern); + await updateRules(rules); + }, + [list, updateRules] + ); + + const put = useCallback( + async (pattern, obj) => { + const rules = [...list]; + if (pattern === "*") { + obj.pattern = "*"; + } + const rule = rules.find((r) => r.pattern === pattern); + rule && Object.assign(rule, obj); + await updateRules(rules); + }, + [list, updateRules] + ); + + const merge = useCallback( + async (newRules) => { + const rules = [...list]; + newRules = checkRules(newRules); + newRules.forEach((newRule) => { + const rule = rules.find( + (oldRule) => oldRule.pattern === newRule.pattern + ); + if (rule) { + Object.assign(rule, newRule); + } else { + rules.unshift(newRule); + } + }); + await updateRules(rules); + }, + [list, updateRules] + ); return { list, add, del, put, merge }; } -/** - * 订阅规则 - * @returns - */ -export function useSubrules() { - const setting = useSetting(); - const updateSetting = useSettingUpdate(); - const list = setting?.subrulesList || DEFAULT_SUBRULES_LIST; +// /** +// * 订阅规则 +// * @returns +// */ +// export function useSubrules() { +// const setting = useSetting(); +// const updateSetting = useSettingUpdate(); +// const list = setting?.subrulesList || DEFAULT_SUBRULES_LIST; - const select = async (url) => { - const subrulesList = [...list]; - subrulesList.forEach((item) => { - if (item.url === url) { - item.selected = true; - } else { - item.selected = false; - } - }); - await updateSetting({ subrulesList }); - }; +// const select = async (url) => { +// const subrulesList = [...list]; +// subrulesList.forEach((item) => { +// if (item.url === url) { +// item.selected = true; +// } else { +// item.selected = false; +// } +// }); +// await updateSetting({ subrulesList }); +// }; - const add = async (url) => { - const subrulesList = [...list]; - subrulesList.push({ url }); - await updateSetting({ subrulesList }); - }; +// const add = async (url) => { +// const subrulesList = [...list]; +// subrulesList.push({ url }); +// await updateSetting({ subrulesList }); +// }; - const del = async (url) => { - let subrulesList = [...list]; - subrulesList = subrulesList.filter((item) => item.url !== url); - await updateSetting({ subrulesList }); - }; +// const del = async (url) => { +// let subrulesList = [...list]; +// subrulesList = subrulesList.filter((item) => item.url !== url); +// await updateSetting({ subrulesList }); +// }; - return { list, select, add, del }; -} +// return { list, select, add, del }; +// } diff --git a/src/hooks/Setting.js b/src/hooks/Setting.js index 1757bbf..3abfd07 100644 --- a/src/hooks/Setting.js +++ b/src/hooks/Setting.js @@ -1,28 +1,79 @@ -import { STOKEY_SETTING } from "../config"; -import storage from "../libs/storage"; -import { useStorages } from "./Storage"; +import { STOKEY_SETTING, DEFAULT_SETTING } from "../config"; +import { useStorage } from "./Storage"; import { useSync } from "./Sync"; import { trySyncSetting } from "../libs/sync"; +import { createContext, useCallback, useContext } from "react"; + +const SettingContext = createContext({ + setting: null, + updateSetting: async () => {}, +}); + +export function SettingProvider({ children }) { + const { data, update } = useStorage(STOKEY_SETTING, DEFAULT_SETTING); + const { + sync: { settingUpdateAt }, + updateSync, + } = useSync(); + + const updateSetting = useCallback( + async (obj) => { + const updateAt = settingUpdateAt ? Date.now() : 0; + await update(obj); + await updateSync({ settingUpdateAt: updateAt }); + trySyncSetting(); + }, + [settingUpdateAt] + ); + + return ( + + {children} + + ); +} /** - * 设置hook + * 设置 hook * @returns */ export function useSetting() { - const storages = useStorages(); - return storages?.[STOKEY_SETTING]; + return useContext(SettingContext); } -/** - * 更新设置 - * @returns - */ -export function useSettingUpdate() { - const sync = useSync(); - return async (obj) => { - const updateAt = sync.opt?.settingUpdateAt ? Date.now() : 0; - await storage.putObj(STOKEY_SETTING, obj); - await sync.update({ settingUpdateAt: updateAt }); - trySyncSetting(); - }; -} +// export function useSetting() { +// const [setting,setSeting]= useState(null); +// useEffect(()=>{ +// (async ()=>{ +// const +// })() +// },[]) +// } + +// /** +// * 设置hook +// * @returns +// */ +// export function useSetting() { +// const storages = useStorages(); +// return storages?.[STOKEY_SETTING]; +// } + +// /** +// * 更新设置 +// * @returns +// */ +// export function useSettingUpdate() { +// const sync = useSync(); +// return async (obj) => { +// const updateAt = sync.opt?.settingUpdateAt ? Date.now() : 0; +// await storage.putObj(STOKEY_SETTING, obj); +// await sync.update({ settingUpdateAt: updateAt }); +// trySyncSetting(); +// }; +// } diff --git a/src/hooks/Storage.js b/src/hooks/Storage.js index 4f9e59c..5c5f6f6 100644 --- a/src/hooks/Storage.js +++ b/src/hooks/Storage.js @@ -1,91 +1,115 @@ -import { createContext, useContext, useEffect, useState } from "react"; -import { browser, isExt, isGm, isWeb } from "../libs/browser"; -import { - STOKEY_SETTING, - STOKEY_RULES, - STOKEY_SYNC, - DEFAULT_SETTING, - DEFAULT_RULES, - DEFAULT_SYNC, -} from "../config"; -import storage from "../libs/storage"; +import { useCallback, useEffect, useState } from "react"; +import { storage } from "../libs/storage"; -/** - * 默认配置 - */ -export const defaultStorage = { - [STOKEY_SETTING]: DEFAULT_SETTING, - [STOKEY_RULES]: DEFAULT_RULES, - [STOKEY_SYNC]: DEFAULT_SYNC, -}; +export function useStorage(key, defaultVal = null) { + const [data, setData] = useState(defaultVal); -const activeKeys = Object.keys(defaultStorage); + const save = useCallback( + async (val) => { + setData(val); + await storage.setObj(key, val); + }, + [key] + ); -const StoragesContext = createContext(null); + const update = useCallback( + async (obj) => { + setData((pre) => ({ ...pre, ...obj })); + await storage.putObj(key, obj); + }, + [key] + ); -export function StoragesProvider({ children }) { - const [storages, setStorages] = useState(null); - - const handleChanged = (changes) => { - if (isWeb || isGm) { - const { key, oldValue, newValue } = changes; - changes = { - [key]: { - oldValue, - newValue, - }, - }; - } - const newStorages = {}; - Object.entries(changes) - .filter( - ([key, { oldValue, newValue }]) => - activeKeys.includes(key) && oldValue !== newValue - ) - .forEach(([key, { newValue }]) => { - newStorages[key] = JSON.parse(newValue); - }); - if (Object.keys(newStorages).length !== 0) { - setStorages((pre) => ({ ...pre, ...newStorages })); - } - }; + const remove = useCallback(async () => { + setData(null); + await storage.del(key); + }, [key]); useEffect(() => { - // 首次从storage同步配置到内存 (async () => { - const curStorages = {}; - for (const key of activeKeys) { - const val = await storage.get(key); - if (val) { - curStorages[key] = JSON.parse(val); - } else { - await storage.setObj(key, defaultStorage[key]); - curStorages[key] = defaultStorage[key]; - } - } - setStorages(curStorages); + setData(await storage.getObj(key)); })(); + }, [key]); - // 监听storage,并同步到内存中 - storage.onChanged(handleChanged); - - // 解除监听 - return () => { - if (isExt) { - browser.storage.onChanged.removeListener(handleChanged); - } else { - window.removeEventListener("storage", handleChanged); - } - }; - }, []); - - return ( - - {children} - - ); + return { data, save, update, remove }; } -export function useStorages() { - return useContext(StoragesContext); -} +// /** +// * 默认配置 +// */ +// export const defaultStorage = { +// [STOKEY_SETTING]: DEFAULT_SETTING, +// [STOKEY_RULES]: DEFAULT_RULES, +// [STOKEY_SYNC]: DEFAULT_SYNC, +// }; + +// const activeKeys = Object.keys(defaultStorage); + +// const StoragesContext = createContext(null); + +// export function StoragesProvider({ children }) { +// const [storages, setStorages] = useState(null); + +// const handleChanged = (changes) => { +// if (isWeb || isGm) { +// const { key, oldValue, newValue } = changes; +// changes = { +// [key]: { +// oldValue, +// newValue, +// }, +// }; +// } +// const newStorages = {}; +// Object.entries(changes) +// .filter( +// ([key, { oldValue, newValue }]) => +// activeKeys.includes(key) && oldValue !== newValue +// ) +// .forEach(([key, { newValue }]) => { +// newStorages[key] = JSON.parse(newValue); +// }); +// if (Object.keys(newStorages).length !== 0) { +// setStorages((pre) => ({ ...pre, ...newStorages })); +// } +// }; + +// useEffect(() => { +// // 首次从storage同步配置到内存 +// (async () => { +// const curStorages = {}; +// for (const key of activeKeys) { +// const val = await storage.get(key); +// if (val) { +// curStorages[key] = JSON.parse(val); +// } else { +// await storage.setObj(key, defaultStorage[key]); +// curStorages[key] = defaultStorage[key]; +// } +// } +// setStorages(curStorages); +// })(); + +// // 监听storage,并同步到内存中 +// storage.onChanged(handleChanged); + +// // 解除监听 +// return () => { +// if (isExt) { +// browser.storage.onChanged.removeListener(handleChanged); +// } else { +// window.removeEventListener("storage", handleChanged); +// } +// }; +// }, []); + +// return ( +// +// {children} +// +// ); +// } + +// export function useStorages() { +// return useContext(StoragesContext); +// } diff --git a/src/hooks/SubRules.js b/src/hooks/SubRules.js new file mode 100644 index 0000000..982a5b3 --- /dev/null +++ b/src/hooks/SubRules.js @@ -0,0 +1,47 @@ +import { DEFAULT_SUBRULES_LIST } from "../config"; +import { useSetting } from "./Setting"; +import { useCallback } from "react"; + +/** + * 订阅规则 + * @returns + */ +export function useSubRules() { + const { data: setting, update: updateSetting } = useSetting(); + const list = setting?.subRulesList || DEFAULT_SUBRULES_LIST; + + const select = useCallback( + async (url) => { + const subRulesList = [...list]; + subRulesList.forEach((item) => { + if (item.url === url) { + item.selected = true; + } else { + item.selected = false; + } + }); + await updateSetting({ subRulesList }); + }, + [list] + ); + + const add = useCallback( + async (url) => { + const subRulesList = [...list]; + subRulesList.push({ url, selected: false }); + await updateSetting({ subRulesList }); + }, + [list] + ); + + const del = useCallback( + async (url) => { + let subRulesList = [...list]; + subRulesList = subRulesList.filter((item) => item.url !== url); + await updateSetting({ subRulesList }); + }, + [list] + ); + + return { list, select, add, del }; +} diff --git a/src/hooks/Sync.js b/src/hooks/Sync.js index c74aa1e..af85bcd 100644 --- a/src/hooks/Sync.js +++ b/src/hooks/Sync.js @@ -1,20 +1,22 @@ -import { useCallback } from "react"; -import { STOKEY_SYNC } from "../config"; -import storage from "../libs/storage"; -import { useStorages } from "./Storage"; +import { STOKEY_SYNC, DEFAULT_SYNC } from "../config"; +import { useStorage } from "./Storage"; /** * sync hook * @returns */ export function useSync() { - const storages = useStorages(); - const opt = storages?.[STOKEY_SYNC]; - const update = useCallback(async (obj) => { - await storage.putObj(STOKEY_SYNC, obj); - }, []); - return { - opt, - update, - }; + const { data, update } = useStorage(STOKEY_SYNC, DEFAULT_SYNC); + return { sync: data, updateSync: update }; } +// export function useSync() { +// const storages = useStorages(); +// const opt = storages?.[STOKEY_SYNC]; +// const update = useCallback(async (obj) => { +// await storage.putObj(STOKEY_SYNC, obj); +// }, []); +// return { +// opt, +// update, +// }; +// } diff --git a/src/hooks/Theme.js b/src/hooks/Theme.js index 19e4d5e..7349c3f 100644 --- a/src/hooks/Theme.js +++ b/src/hooks/Theme.js @@ -9,8 +9,8 @@ import { THEME_DARK, THEME_LIGHT } from "../config"; * @param {*} param0 * @returns */ -export default function MuiThemeProvider({ children, options }) { - const darkMode = useDarkMode(); +export default function Theme({ children, options }) { + const { darkMode } = useDarkMode(); const theme = useMemo(() => { return createTheme({ palette: { diff --git a/src/hooks/Translate.js b/src/hooks/Translate.js index e175019..6a76d71 100644 --- a/src/hooks/Translate.js +++ b/src/hooks/Translate.js @@ -1,15 +1,16 @@ import { useEffect } from "react"; import { useState } from "react"; -import { detectLang } from "../libs"; +import { detectLang } from "../libs/browser"; import { apiTranslate } from "../apis"; /** * 翻译hook * @param {*} q * @param {*} rule + * @param {*} setting * @returns */ -export function useTranslate(q, rule) { +export function useTranslate(q, rule, setting) { const [text, setText] = useState(""); const [loading, setLoading] = useState(false); const [sameLang, setSamelang] = useState(false); @@ -30,6 +31,7 @@ export function useTranslate(q, rule) { q, fromLang, toLang, + setting, }); setText(trText); setSamelang(isSame); @@ -40,7 +42,7 @@ export function useTranslate(q, rule) { setLoading(false); } })(); - }, [q, translator, fromLang, toLang]); + }, [q, translator, fromLang, toLang, setting]); return { text, sameLang, loading }; } diff --git a/src/libs/browser.js b/src/libs/browser.js index bfb0fd0..db3f0cd 100644 --- a/src/libs/browser.js +++ b/src/libs/browser.js @@ -1,4 +1,4 @@ -import { CLIENT_EXTS, CLIENT_USERSCRIPT, CLIENT_WEB } from "../config"; +// import { CLIENT_EXTS, CLIENT_USERSCRIPT, CLIENT_WEB } from "../config"; /** * 浏览器兼容插件,另可用于判断是插件模式还是网页模式,方便开发 @@ -13,7 +13,21 @@ function _browser() { } export const browser = _browser(); -export const client = process.env.REACT_APP_CLIENT; -export const isExt = CLIENT_EXTS.includes(client); -export const isGm = client === CLIENT_USERSCRIPT; -export const isWeb = client === CLIENT_WEB; +// export const client = process.env.REACT_APP_CLIENT; +// export const isExt = CLIENT_EXTS.includes(client); +// export const isGm = client === CLIENT_USERSCRIPT; +// export const isWeb = client === CLIENT_WEB; + +/** + * 本地语言识别 + * @param {*} q + * @returns + */ +export const detectLang = async (q) => { + try { + const res = await browser?.i18n?.detectLanguage(q); + return res?.languages?.[0]?.language; + } catch (err) { + console.log("[detect lang]", err); + } +}; diff --git a/src/libs/client.js b/src/libs/client.js new file mode 100644 index 0000000..4dfdd77 --- /dev/null +++ b/src/libs/client.js @@ -0,0 +1,6 @@ +import { CLIENT_EXTS, CLIENT_USERSCRIPT, CLIENT_WEB } from "../config"; + +export const client = process.env.REACT_APP_CLIENT; +export const isExt = CLIENT_EXTS.includes(client); +export const isGm = client === CLIENT_USERSCRIPT; +export const isWeb = client === CLIENT_WEB; diff --git a/src/libs/fetch.js b/src/libs/fetch.js index a62ae9e..e913799 100644 --- a/src/libs/fetch.js +++ b/src/libs/fetch.js @@ -1,4 +1,4 @@ -import { isExt, isGm } from "./browser"; +import { isExt, isGm } from "./client"; import { sendMsg } from "./msg"; import { taskPool } from "./pool"; import { diff --git a/src/libs/index.js b/src/libs/index.js index b6aae6c..78e6355 100644 --- a/src/libs/index.js +++ b/src/libs/index.js @@ -1,108 +1,12 @@ -import storage from "./storage"; -import { - DEFAULT_SETTING, - STOKEY_SETTING, - STOKEY_RULES, - STOKEY_FAB, - GLOBLA_RULE, - GLOBAL_KEY, - DEFAULT_SUBRULES_LIST, -} from "../config"; -import { browser } from "./browser"; -import { isMatch } from "./utils"; -import { loadSubRules } from "./rules"; +import { CACHE_NAME } from "../config"; /** - * 查询storage中的设置 - * @returns + * 清除缓存数据 */ -export const getSetting = async () => ({ - ...DEFAULT_SETTING, - ...((await storage.getObj(STOKEY_SETTING)) || {}), -}); - -/** - * 查询规则列表 - * @returns - */ -export const getRules = async () => (await storage.getObj(STOKEY_RULES)) || []; - -/** - * 查询fab位置信息 - * @returns - */ -export const getFab = async () => (await storage.getObj(STOKEY_FAB)) || {}; - -/** - * 设置fab位置信息 - * @returns - */ -export const setFab = async (obj) => await storage.setObj(STOKEY_FAB, obj); - -/** - * 根据href匹配规则 - * @param {*} rules - * @param {string} href - * @returns - */ -export const matchRule = async ( - rules, - href, - { injectRules = true, subrulesList = DEFAULT_SUBRULES_LIST } -) => { - rules = [...rules]; - if (injectRules) { - try { - const selectedSub = subrulesList.find((item) => item.selected); - if (selectedSub?.url) { - const subRules = await loadSubRules(selectedSub.url); - rules.splice(-1, 0, ...subRules); - } - } catch (err) { - console.log("[load injectRules]", err); - } - } - - const rule = rules.find((r) => - r.pattern.split(",").some((p) => isMatch(href, p.trim())) - ); - - const globalRule = - rules.find((r) => r.pattern.split(",").some((p) => p.trim() === "*")) || - GLOBLA_RULE; - - if (!rule) { - return globalRule; - } - - rule.selector = - rule?.selector?.trim() || - globalRule?.selector?.trim() || - GLOBLA_RULE.selector; - - rule.bgColor = rule?.bgColor?.trim() || globalRule?.bgColor?.trim(); - - ["translator", "fromLang", "toLang", "textStyle", "transOpen"].forEach( - (key) => { - if (rule[key] === GLOBAL_KEY) { - rule[key] = globalRule[key]; - } - } - ); - - return rule; -}; - -/** - * 本地语言识别 - * @param {*} q - * @returns - */ -export const detectLang = async (q) => { +export const tryClearCaches = async () => { try { - const res = await browser?.i18n?.detectLanguage(q); - return res?.languages?.[0]?.language; + caches.delete(CACHE_NAME); } catch (err) { - console.log("[detect lang]", err); + console.log("[clean caches]", err.message); } }; diff --git a/src/libs/rules.js b/src/libs/rules.js index 447019f..b8b4c89 100644 --- a/src/libs/rules.js +++ b/src/libs/rules.js @@ -1,18 +1,78 @@ -import storage from "./storage"; -import { fetchPolyfill } from "./fetch"; -import { matchValue, type } from "./utils"; import { - STOKEY_RULESCACHE_PREFIX, + getSyncWithDefault, + updateSync, + getSubRulesWithDefault, + getSubRules, + delSubRules, + setSubRules, +} from "./storage"; +import { fetchPolyfill } from "./fetch"; +import { matchValue, type, isMatch } from "./utils"; +import { GLOBAL_KEY, OPT_TRANS_ALL, OPT_STYLE_ALL, OPT_LANGS_FROM, OPT_LANGS_TO, + GLOBLA_RULE, + DEFAULT_SUBRULES_LIST, } from "../config"; -import { syncOpt } from "./sync"; -const fromLangs = OPT_LANGS_FROM.map((item) => item[0]); -const toLangs = OPT_LANGS_TO.map((item) => item[0]); +// import { syncOpt } from "./sync"; + +/** + * 根据href匹配规则 + * @param {*} rules + * @param {string} href + * @returns + */ +export const matchRule = async ( + rules, + href, + { injectRules = true, subrulesList = DEFAULT_SUBRULES_LIST } +) => { + rules = [...rules]; + if (injectRules) { + try { + const selectedSub = subrulesList.find((item) => item.selected); + if (selectedSub?.url) { + const subRules = await loadSubRules(selectedSub.url); + rules.splice(-1, 0, ...subRules); + } + } catch (err) { + console.log("[load injectRules]", err); + } + } + + const rule = rules.find((r) => + r.pattern.split(",").some((p) => isMatch(href, p.trim())) + ); + + const globalRule = + rules.find((r) => r.pattern.split(",").some((p) => p.trim() === "*")) || + GLOBLA_RULE; + + if (!rule) { + return globalRule; + } + + rule.selector = + rule?.selector?.trim() || + globalRule?.selector?.trim() || + GLOBLA_RULE.selector; + + rule.bgColor = rule?.bgColor?.trim() || globalRule?.bgColor?.trim(); + + ["translator", "fromLang", "toLang", "textStyle", "transOpen"].forEach( + (key) => { + if (rule[key] === GLOBAL_KEY) { + rule[key] = globalRule[key]; + } + } + ); + + return rule; +}; /** * 检查过滤rules @@ -27,6 +87,8 @@ export const checkRules = (rules) => { throw new Error("data error"); } + const fromLangs = OPT_LANGS_FROM.map((item) => item[0]); + const toLangs = OPT_LANGS_TO.map((item) => item[0]); const patternSet = new Set(); rules = rules .filter((rule) => type(rule) === "object") @@ -62,84 +124,18 @@ export const checkRules = (rules) => { return rules; }; -/** - * 订阅规则的本地缓存 - */ -export const rulesCache = { - fetch: async (url, isBg = false) => { - const res = await fetchPolyfill(url, { isBg }); - const rules = checkRules(res).filter( - (rule) => rule.pattern.replaceAll(GLOBAL_KEY, "") !== "" - ); - return rules; - }, - set: async (url, rules) => { - await storage.setObj(`${STOKEY_RULESCACHE_PREFIX}${url}`, rules); - }, - get: async (url) => { - return await storage.getObj(`${STOKEY_RULESCACHE_PREFIX}${url}`); - }, - del: async (url) => { - await storage.del(`${STOKEY_RULESCACHE_PREFIX}${url}`); - }, -}; - -/** - * 同步订阅规则 - * @param {*} url - * @returns - */ -export const syncSubRules = async (url, isBg = false) => { - const rules = await rulesCache.fetch(url, isBg); - if (rules.length > 0) { - await rulesCache.set(url, rules); - } - return rules; -}; - -/** - * 同步所有订阅规则 - * @param {*} url - * @returns - */ -export const syncAllSubRules = async (subrulesList, isBg = false) => { - for (let subrules of subrulesList) { - try { - await syncSubRules(subrules.url, isBg); - } catch (err) { - console.log(`[sync subrule error]: ${subrules.url}`, err); - } - } -}; - -/** - * 根据时间同步所有订阅规则 - * @param {*} url - * @returns - */ -export const trySyncAllSubRules = async ({ subrulesList }, isBg = false) => { - try { - const { subRulesSyncAt } = await syncOpt.load(); - const now = Date.now(); - const interval = 24 * 60 * 60 * 1000; // 间隔一天 - if (now - subRulesSyncAt > interval) { - await syncAllSubRules(subrulesList, isBg); - await syncOpt.update({ subRulesSyncAt: now }); - } - } catch (err) { - console.log("[try sync all subrules]", err); - } -}; - -/** - * 从缓存或远程加载订阅规则 - * @param {*} url - * @returns - */ -export const loadSubRules = async (url) => { - const rules = await rulesCache.get(url); - if (rules?.length) { - return rules; - } - return await syncSubRules(url); -}; +// /** +// * 订阅规则的本地缓存 +// */ +// export const rulesCache = { +// fetch: async (url, isBg = false) => { +// const res = await fetchPolyfill(url, { isBg }); +// const rules = checkRules(res).filter( +// (rule) => rule.pattern.replaceAll(GLOBAL_KEY, "") !== "" +// ); +// return rules; +// }, +// set: (url, rules) => setSubRules(url, rules), +// get: (url) => getSubRulesWithDefault(url), +// del: (url) => delSubRules(url), +// }; diff --git a/src/libs/storage.js b/src/libs/storage.js index d4eaacb..7a1dae1 100644 --- a/src/libs/storage.js +++ b/src/libs/storage.js @@ -1,28 +1,41 @@ -import { browser, isExt, isGm } from "./browser"; +import { + STOKEY_SETTING, + STOKEY_RULES, + STOKEY_FAB, + STOKEY_SYNC, + STOKEY_MSAUTH, + STOKEY_RULESCACHE_PREFIX, + DEFAULT_SETTING, + DEFAULT_RULES, + DEFAULT_SYNC, + BUILTIN_RULES, +} from "../config"; +import { browser, isExt, isGm } from "./client"; +// import { APP_NAME } from "../config/app"; async function set(key, val) { if (isExt) { await browser.storage.local.set({ [key]: val }); } else if (isGm) { - const oldValue = await (window.KISS_GM || GM).getValue(key); + // const oldValue = await (window.KISS_GM || GM).getValue(key); await (window.KISS_GM || GM).setValue(key, val); - window.dispatchEvent( - new StorageEvent("storage", { - key, - oldValue, - newValue: val, - }) - ); + // window.dispatchEvent( + // new StorageEvent("storage", { + // key, + // oldValue, + // newValue: val, + // }) + // ); } else { - const oldValue = window.localStorage.getItem(key); + // const oldValue = window.localStorage.getItem(key); window.localStorage.setItem(key, val); - window.dispatchEvent( - new StorageEvent("storage", { - key, - oldValue, - newValue: val, - }) - ); + // window.dispatchEvent( + // new StorageEvent("storage", { + // key, + // oldValue, + // newValue: val, + // }) + // ); } } @@ -41,25 +54,25 @@ async function del(key) { if (isExt) { await browser.storage.local.remove([key]); } else if (isGm) { - const oldValue = await (window.KISS_GM || GM).getValue(key); + // const oldValue = await (window.KISS_GM || GM).getValue(key); await (window.KISS_GM || GM).deleteValue(key); - window.dispatchEvent( - new StorageEvent("storage", { - key, - oldValue, - newValue: null, - }) - ); + // window.dispatchEvent( + // new StorageEvent("storage", { + // key, + // oldValue, + // newValue: null, + // }) + // ); } else { - const oldValue = window.localStorage.getItem(key); + // const oldValue = window.localStorage.getItem(key); window.localStorage.removeItem(key); - window.dispatchEvent( - new StorageEvent("storage", { - key, - oldValue, - newValue: null, - }) - ); + // window.dispatchEvent( + // new StorageEvent("storage", { + // key, + // oldValue, + // newValue: null, + // }) + // ); } } @@ -83,22 +96,22 @@ async function putObj(key, obj) { await setObj(key, { ...cur, ...obj }); } -/** - * 监听storage事件 - * @param {*} handleChanged - */ -function onChanged(handleChanged) { - if (isExt) { - browser.storage.onChanged.addListener(handleChanged); - } else { - window.addEventListener("storage", handleChanged); - } -} +// /** +// * 监听storage事件 +// * @param {*} handleChanged +// */ +// function onChanged(handleChanged) { +// if (isExt) { +// browser.storage.onChanged.addListener(handleChanged); +// } else { +// window.addEventListener("storage", handleChanged); +// } +// } /** * 对storage的封装 */ -const storage = { +export const storage = { get, set, del, @@ -106,7 +119,70 @@ const storage = { trySetObj, getObj, putObj, - onChanged, + // onChanged, }; -export default storage; +/** + * 设置信息 + */ +export const getSetting = () => getObj(STOKEY_SETTING); +export const getSettingWithDefault = async () => ({ + ...DEFAULT_SETTING, + ...((await getSetting()) || {}), +}); +export const setSetting = (val) => setObj(STOKEY_SETTING, val); +export const updateSetting = (obj) => putObj(STOKEY_SETTING, obj); + +/** + * 规则列表 + */ +export const getRules = () => getObj(STOKEY_RULES); +export const getRulesWithDefault = async () => + (await getRules()) || DEFAULT_RULES; +export const setRules = (val) => setObj(STOKEY_RULES, val); + +/** + * 订阅规则 + */ +export const getSubRules = (url) => getObj(STOKEY_RULESCACHE_PREFIX + url); +export const getSubRulesWithDefault = async () => (await getSubRules()) || []; +export const delSubRules = (url) => del(STOKEY_RULESCACHE_PREFIX + url); +export const setSubRules = (url, val) => + setObj(STOKEY_RULESCACHE_PREFIX + url, val); + +/** + * fab位置 + */ +export const getFab = () => getObj(STOKEY_FAB); +export const getFabWithDefault = async () => (await getFab()) || {}; +export const setFab = (obj) => setObj(STOKEY_FAB, obj); + +/** + * 数据同步 + */ +export const getSync = () => getObj(STOKEY_SYNC); +export const getSyncWithDefault = async () => (await getSync()) || DEFAULT_SYNC; +export const updateSync = (obj) => putObj(STOKEY_SYNC, obj); + +/** + * ms auth + */ +export const getMsauth = () => getObj(STOKEY_MSAUTH); +export const setMsauth = (val) => setObj(STOKEY_MSAUTH, val); + +/** + * 存入默认数据 + */ +export const tryInitDefaultData = async () => { + try { + await trySetObj(STOKEY_SETTING, DEFAULT_SETTING); + await trySetObj(STOKEY_RULES, DEFAULT_RULES); + await trySetObj(STOKEY_SYNC, DEFAULT_SYNC); + await trySetObj( + `${STOKEY_RULESCACHE_PREFIX}${process.env.REACT_APP_RULESURL}`, + BUILTIN_RULES + ); + } catch (err) { + console.log("[init default]", err); + } +}; diff --git a/src/libs/subRules.js b/src/libs/subRules.js new file mode 100644 index 0000000..e6deb1b --- /dev/null +++ b/src/libs/subRules.js @@ -0,0 +1,62 @@ +import { getSyncWithDefault, updateSync } from "./storage"; +import { apiFetchRules } from "../apis"; + +/** + * 同步订阅规则 + * @param {*} url + * @returns + */ +export const syncSubRules = async (url, isBg = false) => { + const rules = await apiFetchRules(url, isBg); + if (rules.length > 0) { + await rulesCache.set(url, rules); + } + return rules; +}; + +/** + * 同步所有订阅规则 + * @param {*} url + * @returns + */ +export const syncAllSubRules = async (subrulesList, isBg = false) => { + for (let subrules of subrulesList) { + try { + await syncSubRules(subrules.url, isBg); + } catch (err) { + console.log(`[sync subrule error]: ${subrules.url}`, err); + } + } +}; + +/** + * 根据时间同步所有订阅规则 + * @param {*} url + * @returns + */ +export const trySyncAllSubRules = async ({ subrulesList }, isBg = false) => { + try { + const { subRulesSyncAt } = await getSyncWithDefault(); + const now = Date.now(); + const interval = 24 * 60 * 60 * 1000; // 间隔一天 + if (now - subRulesSyncAt > interval) { + await syncAllSubRules(subrulesList, isBg); + await updateSync({ subRulesSyncAt: now }); + } + } catch (err) { + console.log("[try sync all subrules]", err); + } +}; + +/** + * 从缓存或远程加载订阅规则 + * @param {*} url + * @returns + */ +export const loadOrFetchSubRules = async (url) => { + const rules = await apiFetchRules(url); + if (rules?.length) { + return rules; + } + return await syncSubRules(url); +}; diff --git a/src/libs/sync.js b/src/libs/sync.js index fd44bf9..f21af0f 100644 --- a/src/libs/sync.js +++ b/src/libs/sync.js @@ -8,27 +8,27 @@ import { STOKEY_RULES, KV_SALT_SHARE, } from "../config"; -import storage from "../libs/storage"; +import { storage, getSyncWithDefault, updateSync } from "../libs/storage"; import { getSetting, getRules } from "."; import { apiSyncData } from "../apis"; import { sha256 } from "./utils"; -/** - * 同步相关数据 - */ -export const syncOpt = { - load: async () => (await storage.getObj(STOKEY_SYNC)) || DEFAULT_SYNC, - update: async (obj) => { - await storage.putObj(STOKEY_SYNC, obj); - }, -}; +// /** +// * 同步相关数据 +// */ +// export const syncOpt = { +// load: async () => (await storage.getObj(STOKEY_SYNC)) || DEFAULT_SYNC, +// update: async (obj) => { +// await storage.putObj(STOKEY_SYNC, obj); +// }, +// }; /** * 同步设置 * @returns */ -export const syncSetting = async (isBg = false) => { - const { syncUrl, syncKey, settingUpdateAt } = await syncOpt.load(); +const syncSetting = async (isBg = false) => { + const { syncUrl, syncKey, settingUpdateAt } = await getSyncWithDefault(); if (!syncUrl || !syncKey) { return; } @@ -46,13 +46,13 @@ export const syncSetting = async (isBg = false) => { ); if (res && res.updateAt > settingUpdateAt) { - await syncOpt.update({ + await updateSync({ settingUpdateAt: res.updateAt, settingSyncAt: res.updateAt, }); await storage.setObj(STOKEY_SETTING, res.value); } else { - await syncOpt.update({ settingSyncAt: res.updateAt }); + await updateSync({ settingSyncAt: res.updateAt }); } }; @@ -68,8 +68,8 @@ export const trySyncSetting = async (isBg = false) => { * 同步规则 * @returns */ -export const syncRules = async (isBg = false) => { - const { syncUrl, syncKey, rulesUpdateAt } = await syncOpt.load(); +const syncRules = async (isBg = false) => { + const { syncUrl, syncKey, rulesUpdateAt } = await getSyncWithDefault(); if (!syncUrl || !syncKey) { return; } @@ -87,13 +87,13 @@ export const syncRules = async (isBg = false) => { ); if (res && res.updateAt > rulesUpdateAt) { - await syncOpt.update({ + await updateSync({ rulesUpdateAt: res.updateAt, rulesSyncAt: res.updateAt, }); await storage.setObj(STOKEY_RULES, res.value); } else { - await syncOpt.update({ rulesSyncAt: res.updateAt }); + await updateSync({ rulesSyncAt: res.updateAt }); } }; diff --git a/src/libs/translator.js b/src/libs/translator.js index 5140da2..1987824 100644 --- a/src/libs/translator.js +++ b/src/libs/translator.js @@ -12,14 +12,16 @@ import { import Content from "../views/Content"; import { fetchUpdate, fetchClear } from "./fetch"; import { debounce } from "./utils"; +import { isExt } from "./client"; /** * 翻译类 */ export class Translator { _rule = {}; - _minLength = 0; - _maxLength = 0; + _setting = {}; + _rootNodes = new Set(); + _tranNodes = new Map(); _skipNodeNames = [ APP_LCNAME, "style", @@ -36,8 +38,6 @@ export class Translator { "script", "iframe", ]; - _rootNodes = new Set(); - _tranNodes = new Map(); // 显示 _interseObserver = new IntersectionObserver( @@ -89,12 +89,14 @@ export class Translator { }; }; - constructor(rule, { fetchInterval, fetchLimit, minLength, maxLength }) { + constructor(rule, setting) { + const { fetchInterval, fetchLimit } = setting; fetchUpdate(fetchInterval, fetchLimit); this._overrideAttachShadow(); - this._minLength = minLength ?? TRANS_MIN_LENGTH; - this._maxLength = maxLength ?? TRANS_MAX_LENGTH; - this.rule = rule; + + this._setting = setting; + this._rule = rule; + if (rule.transOpen === "true") { this._register(); } @@ -268,7 +270,11 @@ export class Translator { this._tranNodes.set(el, q); // 太长或太短 - if (!q || q.length < this._minLength || q.length > this._maxLength) { + if ( + !q || + q.length < (this._setting.minLength ?? TRANS_MIN_LENGTH) || + q.length > (this._setting.maxLength ?? TRANS_MAX_LENGTH) + ) { return; } diff --git a/src/popup.js b/src/popup.js index 576bc6b..cb20c38 100644 --- a/src/popup.js +++ b/src/popup.js @@ -1,16 +1,16 @@ import React from "react"; import ReactDOM from "react-dom/client"; -import { StoragesProvider } from "./hooks/Storage"; +import { SettingProvider } from "./hooks/Setting"; import ThemeProvider from "./hooks/Theme"; import Popup from "./views/Popup"; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( - + - + ); diff --git a/src/userscript.js b/src/userscript.js index 695e4e5..5506626 100644 --- a/src/userscript.js +++ b/src/userscript.js @@ -5,8 +5,8 @@ import createCache from "@emotion/cache"; import { CacheProvider } from "@emotion/react"; import { getSetting, getRules, matchRule, getFab } from "./libs"; import { Translator } from "./libs/translator"; -import { trySyncAllSubRules } from "./libs/rules"; -import { isGm } from "./libs/browser"; +import { trySyncAllSubRules } from "./libs/subRules"; +import { isGm } from "./libs/client"; import { MSG_TRANS_TOGGLE, MSG_TRANS_PUTRULE } from "./config"; import { isIframe } from "./libs/iframe"; import { handlePing, injectScript } from "./libs/gm"; diff --git a/src/views/Action/Draggable.js b/src/views/Action/Draggable.js index 2466306..a78f3e4 100644 --- a/src/views/Action/Draggable.js +++ b/src/views/Action/Draggable.js @@ -1,7 +1,7 @@ import { useCallback, useEffect, useMemo, useState } from "react"; import { limitNumber } from "../../libs/utils"; import { isMobile } from "../../libs/mobile"; -import { setFab } from "../../libs"; +import { setFab } from "../../libs/storage"; const getEdgePosition = ( { x: left, y: top, edge }, diff --git a/src/views/Action/index.js b/src/views/Action/index.js index 7895b5b..263be6d 100644 --- a/src/views/Action/index.js +++ b/src/views/Action/index.js @@ -8,7 +8,7 @@ import IconButton from "@mui/material/IconButton"; import CloseIcon from "@mui/icons-material/Close"; import Stack from "@mui/material/Stack"; import { useEffect, useState, useMemo, useCallback } from "react"; -import { StoragesProvider } from "../../hooks/Storage"; +import { SettingProvider } from "../../hooks/Setting"; import Popup from "../Popup"; import { debounce } from "../../libs/utils"; @@ -81,7 +81,7 @@ export default function Action({ translator, fab }) { }; return ( - + - + ); } diff --git a/src/views/Content/index.js b/src/views/Content/index.js index 1e1b2ae..745a0ae 100644 --- a/src/views/Content/index.js +++ b/src/views/Content/index.js @@ -16,7 +16,7 @@ import { useTranslate } from "../../hooks/Translate"; export default function Content({ q, translator }) { const [rule, setRule] = useState(translator.rule); const [hover, setHover] = useState(false); - const { text, sameLang, loading } = useTranslate(q, rule); + const { text, sameLang, loading } = useTranslate(q, rule, translator.setting); const { textStyle, bgColor } = rule; const handleMouseEnter = () => { diff --git a/src/views/Options/Header.js b/src/views/Options/Header.js index ff3322f..6d89fe2 100644 --- a/src/views/Options/Header.js +++ b/src/views/Options/Header.js @@ -4,7 +4,6 @@ import IconButton from "@mui/material/IconButton"; import MenuIcon from "@mui/icons-material/Menu"; import Toolbar from "@mui/material/Toolbar"; import Box from "@mui/material/Box"; -import { useDarkModeSwitch } from "../../hooks/ColorMode"; import { useDarkMode } from "../../hooks/ColorMode"; import LightModeIcon from "@mui/icons-material/LightMode"; import DarkModeIcon from "@mui/icons-material/DarkMode"; @@ -14,8 +13,7 @@ import { useI18n } from "../../hooks/I18n"; function Header(props) { const i18n = useI18n(); const { onDrawerToggle } = props; - const switchColorMode = useDarkModeSwitch(); - const darkMode = useDarkMode(); + const { darkMode, toggleDarkMode } = useDarkMode(); return ( {`${i18n("app_name")} v${process.env.REACT_APP_VERSION}`} - + {darkMode ? : } diff --git a/src/views/Options/Setting.js b/src/views/Options/Setting.js index 2851092..2888d0b 100644 --- a/src/views/Options/Setting.js +++ b/src/views/Options/Setting.js @@ -5,7 +5,7 @@ import TextField from "@mui/material/TextField"; import MenuItem from "@mui/material/MenuItem"; import FormControl from "@mui/material/FormControl"; import Select from "@mui/material/Select"; -import { useSetting, useSettingUpdate } from "../../hooks/Setting"; +import { useSetting } from "../../hooks/Setting"; import { limitNumber, debounce } from "../../libs/utils"; import { useI18n } from "../../hooks/I18n"; import { UI_LANGS } from "../../config"; @@ -13,8 +13,7 @@ import { useMemo } from "react"; export default function Settings() { const i18n = useI18n(); - const setting = useSetting(); - const updateSetting = useSettingUpdate(); + const { setting, updateSetting } = useSetting(); const handleChange = useMemo( () => diff --git a/src/views/Options/index.js b/src/views/Options/index.js index cd749c0..cfafb26 100644 --- a/src/views/Options/index.js +++ b/src/views/Options/index.js @@ -4,10 +4,10 @@ import Rules from "./Rules"; import Setting from "./Setting"; import Layout from "./Layout"; import SyncSetting from "./SyncSetting"; -import { StoragesProvider } from "../../hooks/Storage"; +import { SettingProvider } from "../../hooks/Setting"; import ThemeProvider from "../../hooks/Theme"; import { useEffect, useState } from "react"; -import { isGm } from "../../libs/browser"; +import { isGm } from "../../libs/client"; import { sleep } from "../../libs/utils"; import CircularProgress from "@mui/material/CircularProgress"; import { trySyncAll } from "../../libs/sync"; @@ -89,7 +89,7 @@ export default function Options() { } return ( - + @@ -104,6 +104,6 @@ export default function Options() { - + ); } diff --git a/src/views/Popup/index.js b/src/views/Popup/index.js index 40d36e8..0ffbaa9 100644 --- a/src/views/Popup/index.js +++ b/src/views/Popup/index.js @@ -6,7 +6,8 @@ import FormControlLabel from "@mui/material/FormControlLabel"; import Switch from "@mui/material/Switch"; import Button from "@mui/material/Button"; import { sendTabMsg } from "../../libs/msg"; -import { browser, isExt } from "../../libs/browser"; +import { browser } from "../../libs/browser"; +import { isExt } from "../../libs/client"; import { useI18n } from "../../hooks/I18n"; import TextField from "@mui/material/TextField"; import {