diff --git a/src/config/i18n.js b/src/config/i18n.js index 7a3f8fa..095d125 100644 --- a/src/config/i18n.js +++ b/src/config/i18n.js @@ -88,6 +88,10 @@ export const I18N = { zh: `样式颜色`, en: `Style Color`, }, + remain_unchanged: { + zh: `保留不变`, + en: `Remain Unchanged`, + }, google_api: { zh: `谷歌翻译接口`, en: `Google Translate API`, @@ -136,6 +140,10 @@ export const I18N = { zh: `订阅规则`, en: `Subscribe Rules`, }, + overwrite_subscribe_rules: { + zh: `覆写订阅规则`, + en: `Overwrite Subscribe Rules`, + }, subscribe_url: { zh: `订阅地址`, en: `Subscribe URL`, diff --git a/src/config/index.js b/src/config/index.js index be87f63..bf5c4c4 100644 --- a/src/config/index.js +++ b/src/config/index.js @@ -1,13 +1,23 @@ import { DEFAULT_SELECTOR, GLOBAL_KEY, + REMAIN_KEY, SHADOW_KEY, DEFAULT_RULE, + DEFAULT_OW_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, APP_LCNAME }; +export { + GLOBAL_KEY, + REMAIN_KEY, + SHADOW_KEY, + DEFAULT_RULE, + DEFAULT_OW_RULE, + BUILTIN_RULES, + APP_LCNAME, +}; export const STOKEY_MSAUTH = `${APP_NAME}_msauth`; export const STOKEY_SETTING = `${APP_NAME}_setting`; @@ -150,19 +160,6 @@ export const PROMPT_PLACE_TO = "{{to}}"; // 占位符 export const DEFAULT_COLOR = "#209CEE"; // 默认高亮背景色/线条颜色 -export const DEFAULT_DIY_STYLE = `color: #666; -background: linear-gradient( - 45deg, - LightGreen 20%, - LightPink 20% 40%, - LightSalmon 40% 60%, - LightSeaGreen 60% 80%, - LightSkyBlue 80% -); -&:hover { - color: #333; -};`; - // 全局规则 export const GLOBLA_RULE = { pattern: "*", @@ -203,6 +200,7 @@ export const DEFAULT_SETTING = { clearCache: false, // 是否在浏览器下次启动时清除缓存 injectRules: true, // 是否注入订阅规则 subrulesList: DEFAULT_SUBRULES_LIST, // 订阅列表 + owSubrule: DEFAULT_OW_RULE, // 覆写订阅规则 googleUrl: "https://translate.googleapis.com/translate_a/single", // 谷歌翻译接口 openaiUrl: "https://api.openai.com/v1/chat/completions", openaiKey: "", diff --git a/src/config/rules.js b/src/config/rules.js index bd6f2dd..12f03b9 100644 --- a/src/config/rules.js +++ b/src/config/rules.js @@ -3,6 +3,7 @@ const els = `li, p, h1, h2, h3, h4, h5, h6, dd`; export const DEFAULT_SELECTOR = `:is(${els})`; export const GLOBAL_KEY = "*"; +export const REMAIN_KEY = "-"; export const SHADOW_KEY = ">>>"; @@ -18,6 +19,29 @@ export const DEFAULT_RULE = { textDiyStyle: "", }; +const DEFAULT_DIY_STYLE = `color: #666; +background: linear-gradient( + 45deg, + LightGreen 20%, + LightPink 20% 40%, + LightSalmon 40% 60%, + LightSeaGreen 60% 80%, + LightSkyBlue 80% +); +&:hover { + color: #333; +};`; + +export const DEFAULT_OW_RULE = { + translator: REMAIN_KEY, + fromLang: REMAIN_KEY, + toLang: REMAIN_KEY, + textStyle: REMAIN_KEY, + transOpen: REMAIN_KEY, + bgColor: "", + textDiyStyle: DEFAULT_DIY_STYLE, +}; + const RULES = [ { pattern: `www.google.com/search`, diff --git a/src/hooks/Setting.js b/src/hooks/Setting.js index 03226e1..1272a17 100644 --- a/src/hooks/Setting.js +++ b/src/hooks/Setting.js @@ -22,7 +22,7 @@ export function SettingProvider({ children }) { () => debounce(() => { trySyncSetting(); - }, [1000]), + }, [2000]), [] ); diff --git a/src/hooks/SubRules.js b/src/hooks/SubRules.js index 8bc5012..0c13025 100644 --- a/src/hooks/SubRules.js +++ b/src/hooks/SubRules.js @@ -1,4 +1,4 @@ -import { DEFAULT_SUBRULES_LIST } from "../config"; +import { DEFAULT_SUBRULES_LIST, DEFAULT_OW_RULE } from "../config"; import { useSetting } from "./Setting"; import { useCallback, useEffect, useMemo, useState } from "react"; import { loadOrFetchSubRules } from "../libs/subRules"; @@ -79,3 +79,21 @@ export function useSubRules() { loading, }; } + +/** + * 覆写订阅规则 + * @returns + */ +export function useOwSubRule() { + const { setting, updateSetting } = useSetting(); + const { owSubrule = DEFAULT_OW_RULE } = setting; + + const updateOwSubrule = useCallback( + async (obj) => { + await updateSetting({ owSubrule: { ...owSubrule, ...obj } }); + }, + [owSubrule, updateSetting] + ); + + return { owSubrule, updateOwSubrule }; +} diff --git a/src/libs/rules.js b/src/libs/rules.js index 6b5b07b..5f39e02 100644 --- a/src/libs/rules.js +++ b/src/libs/rules.js @@ -1,12 +1,14 @@ import { matchValue, type, isMatch } from "./utils"; import { GLOBAL_KEY, + REMAIN_KEY, OPT_TRANS_ALL, OPT_STYLE_ALL, OPT_LANGS_FROM, OPT_LANGS_TO, GLOBLA_RULE, DEFAULT_SUBRULES_LIST, + DEFAULT_OW_RULE, } from "../config"; import { loadOrFetchSubRules } from "./subRules"; @@ -19,14 +21,35 @@ import { loadOrFetchSubRules } from "./subRules"; export const matchRule = async ( rules, href, - { injectRules = true, subrulesList = DEFAULT_SUBRULES_LIST } + { + injectRules = true, + subrulesList = DEFAULT_SUBRULES_LIST, + owSubrule = DEFAULT_OW_RULE, + } ) => { rules = [...rules]; if (injectRules) { try { const selectedSub = subrulesList.find((item) => item.selected); if (selectedSub?.url) { - const subRules = await loadOrFetchSubRules(selectedSub.url); + const mixRule = {}; + Object.entries(owSubrule) + .filter(([key, val]) => { + if ( + owSubrule.textStyle === REMAIN_KEY && + (key === "bgColor" || key === "textDiyStyle") + ) { + return false; + } + return val !== REMAIN_KEY; + }) + .forEach(([key, val]) => { + mixRule[key] = val; + }); + + const subRules = (await loadOrFetchSubRules(selectedSub.url)).map( + (item) => ({ ...item, ...mixRule }) + ); rules.splice(-1, 0, ...subRules); } } catch (err) { @@ -39,8 +62,9 @@ export const matchRule = async ( ); const globalRule = - rules.find((r) => r.pattern.split(",").some((p) => p.trim() === "*")) || - GLOBLA_RULE; + rules.find((r) => + r.pattern.split(",").some((p) => p.trim() === GLOBAL_KEY) + ) || GLOBLA_RULE; if (!rule) { return globalRule; @@ -52,7 +76,8 @@ export const matchRule = async ( GLOBLA_RULE.selector; rule.bgColor = rule?.bgColor?.trim() || globalRule?.bgColor?.trim(); - rule.textDiyStyle = rule?.textDiyStyle?.trim() || globalRule?.textDiyStyle?.trim(); + rule.textDiyStyle = + rule?.textDiyStyle?.trim() || globalRule?.textDiyStyle?.trim(); ["translator", "fromLang", "toLang", "textStyle", "transOpen"].forEach( (key) => { diff --git a/src/views/Options/OwSubRule.js b/src/views/Options/OwSubRule.js new file mode 100644 index 0000000..582c508 --- /dev/null +++ b/src/views/Options/OwSubRule.js @@ -0,0 +1,175 @@ +import Box from "@mui/material/Box"; +import Stack from "@mui/material/Stack"; +import TextField from "@mui/material/TextField"; +import { + GLOBAL_KEY, + REMAIN_KEY, + OPT_LANGS_FROM, + OPT_LANGS_TO, + OPT_TRANS_ALL, + OPT_STYLE_ALL, + OPT_STYLE_DIY, + OPT_STYLE_USE_COLOR, +} from "../../config"; +import { useI18n } from "../../hooks/I18n"; +import MenuItem from "@mui/material/MenuItem"; +import Grid from "@mui/material/Grid"; +import { useOwSubRule } from "../../hooks/SubRules"; + +export default function OwSubRule() { + const i18n = useI18n(); + const { owSubrule, updateOwSubrule } = useOwSubRule(); + + const handleChange = (e) => { + e.preventDefault(); + const { name, value } = e.target; + updateOwSubrule({ [name]: value }); + }; + + const { + translator, + fromLang, + toLang, + textStyle, + transOpen, + bgColor, + textDiyStyle, + } = owSubrule; + + const RemainItem = ( + + {i18n("remain_unchanged")} + + ); + + const GlobalItem = ( + + {GLOBAL_KEY} + + ); + + return ( + + + + + + {RemainItem} + {GlobalItem} + {i18n("default_enabled")} + {i18n("default_disabled")} + + + + + {RemainItem} + {GlobalItem} + {OPT_TRANS_ALL.map((item) => ( + + {item} + + ))} + + + + + {RemainItem} + {GlobalItem} + {OPT_LANGS_FROM.map(([lang, name]) => ( + + {name} + + ))} + + + + + {RemainItem} + {GlobalItem} + {OPT_LANGS_TO.map(([lang, name]) => ( + + {name} + + ))} + + + + + {RemainItem} + {GlobalItem} + {OPT_STYLE_ALL.map((item) => ( + + {i18n(item)} + + ))} + + + {OPT_STYLE_USE_COLOR.includes(textStyle) && ( + + + + )} + + + + {textStyle === OPT_STYLE_DIY && ( + + )} + + ); +} diff --git a/src/views/Options/Rules.js b/src/views/Options/Rules.js index d3dd7f3..5593276 100644 --- a/src/views/Options/Rules.js +++ b/src/views/Options/Rules.js @@ -44,6 +44,7 @@ import { useAlert } from "../../hooks/Alert"; import { syncShareRules } from "../../libs/sync"; import { debounce } from "../../libs/utils"; import { delSubRules, getSyncWithDefault } from "../../libs/storage"; +import OwSubRule from "./OwSubRule"; function RuleFields({ rule, rules, setShow, setKeyword }) { const initFormValues = rule || { @@ -140,7 +141,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) { } }; - const globalItem = rule?.pattern !== "*" && ( + const GlobalItem = rule?.pattern !== "*" && ( {GLOBAL_KEY} @@ -187,7 +188,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) { disabled={disabled} onChange={handleChange} > - {globalItem} + {GlobalItem} {i18n("default_enabled")} {i18n("default_disabled")} @@ -203,7 +204,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) { disabled={disabled} onChange={handleChange} > - {globalItem} + {GlobalItem} {OPT_TRANS_ALL.map((item) => ( {item} @@ -222,7 +223,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) { disabled={disabled} onChange={handleChange} > - {globalItem} + {GlobalItem} {OPT_LANGS_FROM.map(([lang, name]) => ( {name} @@ -241,7 +242,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) { disabled={disabled} onChange={handleChange} > - {globalItem} + {GlobalItem} {OPT_LANGS_TO.map(([lang, name]) => ( {name} @@ -260,7 +261,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) { disabled={disabled} onChange={handleChange} > - {globalItem} + {GlobalItem} {OPT_STYLE_ALL.map((item) => ( {i18n(item)} @@ -818,6 +819,7 @@ export default function Rules() { + @@ -826,6 +828,7 @@ export default function Rules() { {activeTab === 1 && } + {activeTab === 2 && } );