feat: Restructured core logic to support automatic page scanning and rich text translation
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@emotion/cache": "^11.11.0",
|
||||
"@emotion/css": "^11.13.5",
|
||||
"@emotion/react": "^11.11.1",
|
||||
"@emotion/styled": "^11.11.0",
|
||||
"@mui/icons-material": "^5.15.15",
|
||||
|
||||
83
pnpm-lock.yaml
generated
83
pnpm-lock.yaml
generated
@@ -11,6 +11,9 @@ importers:
|
||||
'@emotion/cache':
|
||||
specifier: ^11.11.0
|
||||
version: 11.11.0
|
||||
'@emotion/css':
|
||||
specifier: ^11.13.5
|
||||
version: 11.13.5
|
||||
'@emotion/react':
|
||||
specifier: ^11.11.1
|
||||
version: 11.11.1(@types/react@18.2.79)(react@18.2.0)
|
||||
@@ -963,18 +966,33 @@ packages:
|
||||
'@emotion/babel-plugin@11.11.0':
|
||||
resolution: {integrity: sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==}
|
||||
|
||||
'@emotion/babel-plugin@11.13.5':
|
||||
resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==}
|
||||
|
||||
'@emotion/cache@11.11.0':
|
||||
resolution: {integrity: sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==}
|
||||
|
||||
'@emotion/cache@11.14.0':
|
||||
resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==}
|
||||
|
||||
'@emotion/css@11.13.5':
|
||||
resolution: {integrity: sha512-wQdD0Xhkn3Qy2VNcIzbLP9MR8TafI0MJb7BEAXKp+w4+XqErksWR4OXomuDzPsN4InLdGhVe6EYcn2ZIUCpB8w==}
|
||||
|
||||
'@emotion/hash@0.9.1':
|
||||
resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==}
|
||||
|
||||
'@emotion/hash@0.9.2':
|
||||
resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==}
|
||||
|
||||
'@emotion/is-prop-valid@1.2.1':
|
||||
resolution: {integrity: sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==}
|
||||
|
||||
'@emotion/memoize@0.8.1':
|
||||
resolution: {integrity: sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==}
|
||||
|
||||
'@emotion/memoize@0.9.0':
|
||||
resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==}
|
||||
|
||||
'@emotion/react@11.11.1':
|
||||
resolution: {integrity: sha512-5mlW1DquU5HaxjLkfkGN1GA/fvVGdyHURRiX/0FHl2cfIfRxSOfmxEH5YS43edp0OldZrZ+dkBKbngxcNCdZvA==}
|
||||
peerDependencies:
|
||||
@@ -987,9 +1005,15 @@ packages:
|
||||
'@emotion/serialize@1.1.2':
|
||||
resolution: {integrity: sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA==}
|
||||
|
||||
'@emotion/serialize@1.3.3':
|
||||
resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==}
|
||||
|
||||
'@emotion/sheet@1.2.2':
|
||||
resolution: {integrity: sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==}
|
||||
|
||||
'@emotion/sheet@1.4.0':
|
||||
resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==}
|
||||
|
||||
'@emotion/styled@11.11.0':
|
||||
resolution: {integrity: sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==}
|
||||
peerDependencies:
|
||||
@@ -1000,6 +1024,9 @@ packages:
|
||||
'@types/react':
|
||||
optional: true
|
||||
|
||||
'@emotion/unitless@0.10.0':
|
||||
resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==}
|
||||
|
||||
'@emotion/unitless@0.8.1':
|
||||
resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==}
|
||||
|
||||
@@ -1011,9 +1038,15 @@ packages:
|
||||
'@emotion/utils@1.2.1':
|
||||
resolution: {integrity: sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==}
|
||||
|
||||
'@emotion/utils@1.4.2':
|
||||
resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==}
|
||||
|
||||
'@emotion/weak-memoize@0.3.1':
|
||||
resolution: {integrity: sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==}
|
||||
|
||||
'@emotion/weak-memoize@0.4.0':
|
||||
resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==}
|
||||
|
||||
'@eslint-community/eslint-utils@4.4.0':
|
||||
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
@@ -7012,6 +7045,20 @@ snapshots:
|
||||
source-map: 0.5.7
|
||||
stylis: 4.2.0
|
||||
|
||||
'@emotion/babel-plugin@11.13.5':
|
||||
dependencies:
|
||||
'@babel/helper-module-imports': 7.24.3
|
||||
'@babel/runtime': 7.24.4
|
||||
'@emotion/hash': 0.9.2
|
||||
'@emotion/memoize': 0.9.0
|
||||
'@emotion/serialize': 1.3.3
|
||||
babel-plugin-macros: 3.1.0
|
||||
convert-source-map: 1.9.0
|
||||
escape-string-regexp: 4.0.0
|
||||
find-root: 1.1.0
|
||||
source-map: 0.5.7
|
||||
stylis: 4.2.0
|
||||
|
||||
'@emotion/cache@11.11.0':
|
||||
dependencies:
|
||||
'@emotion/memoize': 0.8.1
|
||||
@@ -7020,14 +7067,34 @@ snapshots:
|
||||
'@emotion/weak-memoize': 0.3.1
|
||||
stylis: 4.2.0
|
||||
|
||||
'@emotion/cache@11.14.0':
|
||||
dependencies:
|
||||
'@emotion/memoize': 0.9.0
|
||||
'@emotion/sheet': 1.4.0
|
||||
'@emotion/utils': 1.4.2
|
||||
'@emotion/weak-memoize': 0.4.0
|
||||
stylis: 4.2.0
|
||||
|
||||
'@emotion/css@11.13.5':
|
||||
dependencies:
|
||||
'@emotion/babel-plugin': 11.13.5
|
||||
'@emotion/cache': 11.14.0
|
||||
'@emotion/serialize': 1.3.3
|
||||
'@emotion/sheet': 1.4.0
|
||||
'@emotion/utils': 1.4.2
|
||||
|
||||
'@emotion/hash@0.9.1': {}
|
||||
|
||||
'@emotion/hash@0.9.2': {}
|
||||
|
||||
'@emotion/is-prop-valid@1.2.1':
|
||||
dependencies:
|
||||
'@emotion/memoize': 0.8.1
|
||||
|
||||
'@emotion/memoize@0.8.1': {}
|
||||
|
||||
'@emotion/memoize@0.9.0': {}
|
||||
|
||||
'@emotion/react@11.11.1(@types/react@18.2.79)(react@18.2.0)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.22.15
|
||||
@@ -7050,8 +7117,18 @@ snapshots:
|
||||
'@emotion/utils': 1.2.1
|
||||
csstype: 3.1.2
|
||||
|
||||
'@emotion/serialize@1.3.3':
|
||||
dependencies:
|
||||
'@emotion/hash': 0.9.2
|
||||
'@emotion/memoize': 0.9.0
|
||||
'@emotion/unitless': 0.10.0
|
||||
'@emotion/utils': 1.4.2
|
||||
csstype: 3.1.3
|
||||
|
||||
'@emotion/sheet@1.2.2': {}
|
||||
|
||||
'@emotion/sheet@1.4.0': {}
|
||||
|
||||
'@emotion/styled@11.11.0(@emotion/react@11.11.1(@types/react@18.2.79)(react@18.2.0))(@types/react@18.2.79)(react@18.2.0)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.22.15
|
||||
@@ -7065,6 +7142,8 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/react': 18.2.79
|
||||
|
||||
'@emotion/unitless@0.10.0': {}
|
||||
|
||||
'@emotion/unitless@0.8.1': {}
|
||||
|
||||
'@emotion/use-insertion-effect-with-fallbacks@1.0.1(react@18.2.0)':
|
||||
@@ -7073,8 +7152,12 @@ snapshots:
|
||||
|
||||
'@emotion/utils@1.2.1': {}
|
||||
|
||||
'@emotion/utils@1.4.2': {}
|
||||
|
||||
'@emotion/weak-memoize@0.3.1': {}
|
||||
|
||||
'@emotion/weak-memoize@0.4.0': {}
|
||||
|
||||
'@eslint-community/eslint-utils@4.4.0(eslint@8.57.0)':
|
||||
dependencies:
|
||||
eslint: 8.57.0
|
||||
|
||||
@@ -812,7 +812,7 @@ export const parseTransRes = (
|
||||
case OPT_TRANS_TENCENT:
|
||||
return res?.auto_translation?.map((text) => [text, res?.src_lang]);
|
||||
case OPT_TRANS_VOLCENGINE:
|
||||
return new Map([[0, [res?.translation, res?.detected_language]]]);
|
||||
return [[res?.translation, res?.detected_language]];
|
||||
case OPT_TRANS_OPENAI:
|
||||
case OPT_TRANS_OPENAI_2:
|
||||
case OPT_TRANS_OPENAI_3:
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
MSG_TRANS_GETRULE,
|
||||
MSG_TRANS_PUTRULE,
|
||||
MSG_OPEN_TRANBOX,
|
||||
APP_LCNAME,
|
||||
APP_CONSTS,
|
||||
DEFAULT_TRANBOX_SETTING,
|
||||
} from "./config";
|
||||
import { getFabWithDefault, getSettingWithDefault } from "./libs/storage";
|
||||
@@ -106,7 +106,7 @@ function runIframe(translator) {
|
||||
async function showFab(translator) {
|
||||
const fab = await getFabWithDefault();
|
||||
const $action = document.createElement("div");
|
||||
$action.setAttribute("id", APP_LCNAME);
|
||||
$action.setAttribute("id", APP_CONSTS.fabID);
|
||||
$action.style.fontSize = "0";
|
||||
$action.style.width = "0";
|
||||
$action.style.height = "0";
|
||||
@@ -114,10 +114,11 @@ async function showFab(translator) {
|
||||
const shadowContainer = $action.attachShadow({ mode: "closed" });
|
||||
const emotionRoot = document.createElement("style");
|
||||
const shadowRootElement = document.createElement("div");
|
||||
shadowRootElement.classList.add(`${APP_CONSTS.fabID}_warpper`);
|
||||
shadowContainer.appendChild(emotionRoot);
|
||||
shadowContainer.appendChild(shadowRootElement);
|
||||
const cache = createCache({
|
||||
key: APP_LCNAME,
|
||||
key: APP_CONSTS.fabID,
|
||||
prepend: true,
|
||||
container: emotionRoot,
|
||||
});
|
||||
@@ -151,7 +152,7 @@ function showTransbox(
|
||||
}
|
||||
|
||||
const $tranbox = document.createElement("div");
|
||||
$tranbox.setAttribute("id", "kiss-transbox");
|
||||
$tranbox.setAttribute("id", APP_CONSTS.boxID);
|
||||
$tranbox.style.fontSize = "0";
|
||||
$tranbox.style.width = "0";
|
||||
$tranbox.style.height = "0";
|
||||
@@ -159,12 +160,14 @@ function showTransbox(
|
||||
const shadowContainer = $tranbox.attachShadow({ mode: "closed" });
|
||||
const emotionRoot = document.createElement("style");
|
||||
const shadowRootElement = document.createElement("div");
|
||||
shadowRootElement.classList.add(`KT-transbox`);
|
||||
shadowRootElement.classList.add(`KT-transbox_${darkMode ? "dark" : "light"}`);
|
||||
shadowRootElement.classList.add(`${APP_CONSTS.boxID}_warpper`);
|
||||
shadowRootElement.classList.add(
|
||||
`${APP_CONSTS.boxID}_${darkMode ? "dark" : "light"}`
|
||||
);
|
||||
shadowContainer.appendChild(emotionRoot);
|
||||
shadowContainer.appendChild(shadowRootElement);
|
||||
const cache = createCache({
|
||||
key: "kiss-transbox",
|
||||
key: APP_CONSTS.boxID,
|
||||
prepend: true,
|
||||
container: emotionRoot,
|
||||
});
|
||||
|
||||
@@ -2,6 +2,10 @@ export const APP_NAME = process.env.REACT_APP_NAME.trim()
|
||||
.split(/\s+/)
|
||||
.join("-");
|
||||
export const APP_LCNAME = APP_NAME.toLowerCase();
|
||||
export const APP_CONSTS = {
|
||||
fabID: `${APP_LCNAME}-fab`,
|
||||
boxID: `${APP_LCNAME}-box`,
|
||||
};
|
||||
|
||||
export const THEME_LIGHT = "light";
|
||||
export const THEME_DARK = "dark";
|
||||
|
||||
@@ -243,9 +243,9 @@ export const I18N = {
|
||||
zh_TW: `每次請求間隔時間 (0-5000ms)`,
|
||||
},
|
||||
translate_interval: {
|
||||
zh: `重新翻译间隔时间 (100-5000ms)`,
|
||||
en: `Retranslation Interval (100-5000ms)`,
|
||||
zh_TW: `重新翻譯間隔時間 (100-5000ms)`,
|
||||
zh: `翻译间隔时间 (10-2000ms)`,
|
||||
en: `Translation Interval (10-2000ms)`,
|
||||
zh_TW: `翻譯間隔時間 (10-2000ms)`,
|
||||
},
|
||||
http_timeout: {
|
||||
zh: `请求超时时间 (5000-60000ms)`,
|
||||
@@ -543,9 +543,9 @@ export const I18N = {
|
||||
zh_TW: `1. 支援星號 (*) 萬用字元。2. 多個 URL 請以換行或英文逗號「,」分隔。`,
|
||||
},
|
||||
selector_helper: {
|
||||
zh: `1、遵循CSS选择器语法。2、多个CSS选择器之间用“;”隔开。3、“shadow root”选择器和内部选择器用“>>>”隔开。`,
|
||||
en: `1. Follow CSS selector syntax. 2. Separate multiple CSS selectors with ";". 3. The "shadow root" selector and the internal selector are separated by ">>>".`,
|
||||
zh_TW: `1. 遵循 CSS 選擇器語法。2. 多個 CSS 選擇器以「;」分隔。3.「shadow root」與內部選擇器以「>>>」分隔。`,
|
||||
zh: `1、需要翻译的目标元素。2、开启自动扫描页面后,本设置无效。3、遵循CSS选择器语法。`,
|
||||
en: `1. The target element to be translated. 2. This setting is invalid when automatic page scanning is enabled. 3. Follow the CSS selector syntax.`,
|
||||
zh_TW: `1、需要翻譯的目標元素。 2.開啟自動掃描頁面後,本設定無效。 3.遵循CSS選擇器語法。`,
|
||||
},
|
||||
translate_switch: {
|
||||
zh: `开启翻译`,
|
||||
@@ -573,9 +573,29 @@ export const I18N = {
|
||||
zh_TW: `保留元素選擇器`,
|
||||
},
|
||||
keep_selector_helper: {
|
||||
zh: `1、遵循CSS选择器语法。`,
|
||||
en: `1. Follow CSS selector syntax.`,
|
||||
zh_TW: `1. 遵循 CSS 選擇器語法。`,
|
||||
zh: `1、目标元素下面需要原样保留的子节点。2、遵循CSS选择器语法。`,
|
||||
en: `1. The child nodes under the target element need to remain intact. 2. Follow the CSS selector syntax.`,
|
||||
zh_TW: `1. 目標元素下的子節點需要保持原樣。 2. 遵循 CSS 選擇器語法。`,
|
||||
},
|
||||
root_selector: {
|
||||
zh: `根节点选择器`,
|
||||
en: `Root node selector`,
|
||||
zh_TW: `根節點選擇器`,
|
||||
},
|
||||
root_selector_helper: {
|
||||
zh: `1、用于缩小页面翻译范围。2、遵循CSS选择器语法。`,
|
||||
en: `1. Used to narrow the translation scope of the page. 2. Follow the CSS selector syntax.`,
|
||||
zh_TW: `1.用於縮小頁面翻譯範圍。 2、遵循CSS選擇器語法。`,
|
||||
},
|
||||
ignore_selector: {
|
||||
zh: `不翻译节点选择器`,
|
||||
en: `Ignore node selectors`,
|
||||
zh_TW: `不翻譯節點選擇器`,
|
||||
},
|
||||
ignore_selector_helper: {
|
||||
zh: `1、需要忽略的节点。2、遵循CSS选择器语法。`,
|
||||
en: `1. Nodes to be ignored. 2. Follow CSS selector syntax.`,
|
||||
zh_TW: `1、需要忽略的節點。 2、遵循CSS選擇器語法。`,
|
||||
},
|
||||
terms: {
|
||||
zh: `专业术语`,
|
||||
@@ -608,9 +628,9 @@ export const I18N = {
|
||||
zh_TW: `注入 JS`,
|
||||
},
|
||||
inject_js_helper: {
|
||||
zh: `1、开启翻译时注入运行,关闭翻译时移除。2、随着页面变化,可能会多次注入运行。`,
|
||||
en: `1. Inject and run when translation is turned on, and removed when translation is turned off. 2. As the page changes, it may be injected and run multiple times.`,
|
||||
zh_TW: `1. 開啟翻譯時注入並執行,關閉翻譯時移除。2. 隨頁面變化,可能多次注入與執行。`,
|
||||
zh: `初始化时注入运行,一个页面仅运行一次。`,
|
||||
en: `Injected and run at initialization, and only run once per page.`,
|
||||
zh_TW: `初始化時注入運行,一個頁面僅運行一次。`,
|
||||
},
|
||||
inject_css: {
|
||||
zh: `注入CSS`,
|
||||
@@ -618,14 +638,9 @@ export const I18N = {
|
||||
zh_TW: `注入 CSS`,
|
||||
},
|
||||
inject_css_helper: {
|
||||
zh: `开启翻译时注入,关闭翻译时将移除。`,
|
||||
en: `Injected when translation is enabled and removed when translation is disabled.`,
|
||||
zh_TW: `開啟翻譯時注入,關閉翻譯時會移除。`,
|
||||
},
|
||||
root_selector: {
|
||||
zh: `根选择器`,
|
||||
en: `Root Selector`,
|
||||
zh_TW: `根選擇器`,
|
||||
zh: `初始化时注入运行,一个页面仅运行一次。`,
|
||||
en: `Injected and run at initialization, and only run once per page.`,
|
||||
zh_TW: `初始化時注入運行,一個頁面僅運行一次。`,
|
||||
},
|
||||
fixer_function: {
|
||||
zh: `修复函数`,
|
||||
@@ -1184,9 +1199,9 @@ export const I18N = {
|
||||
zh_TW: `翻譯開始 Hook`,
|
||||
},
|
||||
translate_start_hook_helper: {
|
||||
zh: `翻译开始时运行,入参为: 翻译节点,原文文本,返回:待译文本。`,
|
||||
en: `Run when translation starts, the input parameters are: translation node, original text, and returns: text to be translated.`,
|
||||
zh_TW: `翻譯開始時執行,入參為:翻譯節點、原文文字,回傳:待譯文本。`,
|
||||
zh: `翻译前时运行,入参为: 翻译节点列表。`,
|
||||
en: `Run before translation, input parameters are: translation node list.`,
|
||||
zh_TW: `翻譯前時運行,入參為: 翻譯節點清單。`,
|
||||
},
|
||||
translate_end_hook: {
|
||||
zh: `翻译完成钩子函数`,
|
||||
@@ -1194,9 +1209,9 @@ export const I18N = {
|
||||
zh_TW: `翻譯完成 Hook`,
|
||||
},
|
||||
translate_end_hook_helper: {
|
||||
zh: `翻译完成时运行,入参为: 翻译节点,译文文本,原文文本,保留元素、术语列表,返回:译文文本。`,
|
||||
en: `Run when the translation is completed, the input parameters are: translation node, translation text, original text, retained elements, and returns: translation text.`,
|
||||
zh_TW: `翻譯完成時執行,入參為:翻譯節點、譯文文字、原文文字、保留元素,返回:譯文文本。`,
|
||||
zh: `翻译完成时运行,入参为: 翻译节点列表。`,
|
||||
en: `Run when translation is complete, input parameters are: translation node list.`,
|
||||
zh_TW: `翻譯完成時運行,入參為: 翻譯節點清單。`,
|
||||
},
|
||||
translate_remove_hook: {
|
||||
zh: `翻译移除钩子函数`,
|
||||
@@ -1258,4 +1273,59 @@ export const I18N = {
|
||||
en: `Number of context sessions(1-20)`,
|
||||
zh_TW: `上下文會話數量(1-20)`,
|
||||
},
|
||||
auto_scan_page: {
|
||||
zh: `自动扫描页面`,
|
||||
en: `Auto scan page`,
|
||||
zh_TW: `自動掃描頁面`,
|
||||
},
|
||||
has_rich_text: {
|
||||
zh: `启用富文本翻译`,
|
||||
en: `Enable rich text translation`,
|
||||
zh_TW: `啟用富文本翻譯`,
|
||||
},
|
||||
has_shadowroot: {
|
||||
zh: `扫描Shadowroot`,
|
||||
en: `Scan Shadowroot`,
|
||||
zh_TW: `掃描Shadowroot`,
|
||||
},
|
||||
mousehover_translate: {
|
||||
zh: `鼠标悬停翻译`,
|
||||
en: `Mouseover Translation`,
|
||||
zh_TW: `滑鼠懸停翻譯`,
|
||||
},
|
||||
use_mousehover_translation: {
|
||||
zh: `启用鼠标悬停翻译`,
|
||||
en: `Enable mouseover translation`,
|
||||
zh_TW: `啟用滑鼠懸停翻譯`,
|
||||
},
|
||||
selected_translation_alert: {
|
||||
zh: `划词翻译的开启和关闭请到“规则设置”里面设置。`,
|
||||
en: `To turn selected translation on or off, please go to "Rule Settings".`,
|
||||
zh_TW: `劃詞翻譯的開啟和關閉請到「規則設定」裡面設定。`,
|
||||
},
|
||||
mousehover_key_help: {
|
||||
zh: `默认为“ControlLeft”`,
|
||||
en: `Defaults is "ControlLeft"`,
|
||||
zh_TW: `預設為“ControlLeft”`,
|
||||
},
|
||||
autoscan_alt: {
|
||||
zh: `自动扫描`,
|
||||
en: `Auto Scan`,
|
||||
zh_TW: `自動掃描`,
|
||||
},
|
||||
shadowroot_alt: {
|
||||
zh: `ShadowRoot`,
|
||||
en: `ShadowRoot`,
|
||||
zh_TW: `ShadowRoot`,
|
||||
},
|
||||
richtext_alt: {
|
||||
zh: `富文本`,
|
||||
en: `Rich Text`,
|
||||
zh_TW: `富文本`,
|
||||
},
|
||||
transonly_alt: {
|
||||
zh: `隐藏原文`,
|
||||
en: `Hide Original`,
|
||||
zh_TW: `隱藏原文`,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -58,7 +58,10 @@ export const OPT_TIMING_ALL = [
|
||||
OPT_TIMING_ALT,
|
||||
];
|
||||
|
||||
export const DEFAULT_SELECTOR = `:is(li, p, h1, h2, h3, h4, h5, h6, dd, blockquote, .kiss-p)`;
|
||||
export const DEFAULT_SELECTOR =
|
||||
"h1, h2, h3, h4, h5, h6, li, p, dd, blockquote, figcaption, label, legend";
|
||||
export const DEFAULT_IGNORE_SELECTOR =
|
||||
"button, code, footer, form, header, mark, nav, pre";
|
||||
export const DEFAULT_KEEP_SELECTOR = `code, img, svg, pre`;
|
||||
export const DEFAULT_RULE = {
|
||||
pattern: "", // 匹配网址
|
||||
@@ -77,17 +80,22 @@ export const DEFAULT_RULE = {
|
||||
injectJs: "", // 注入JS
|
||||
injectCss: "", // 注入CSS
|
||||
transOnly: GLOBAL_KEY, // 是否仅显示译文
|
||||
transTiming: GLOBAL_KEY, // 翻译时机/鼠标悬停翻译
|
||||
// transTiming: GLOBAL_KEY, // 翻译时机/鼠标悬停翻译 (暂时作废)
|
||||
transTag: GLOBAL_KEY, // 译文元素标签
|
||||
transTitle: GLOBAL_KEY, // 是否同时翻译页面标题
|
||||
transSelected: GLOBAL_KEY, // 是否启用划词翻译
|
||||
detectRemote: GLOBAL_KEY, // 是否使用远程语言检测
|
||||
skipLangs: [], // 不翻译的语言
|
||||
fixerSelector: "", // 修复函数选择器
|
||||
fixerFunc: GLOBAL_KEY, // 修复函数
|
||||
// fixerSelector: "", // 修复函数选择器 (暂时作废)
|
||||
// fixerFunc: GLOBAL_KEY, // 修复函数 (暂时作废)
|
||||
transStartHook: "", // 钩子函数
|
||||
transEndHook: "", // 钩子函数
|
||||
transRemoveHook: "", // 钩子函数
|
||||
// transRemoveHook: "", // 钩子函数 (暂时作废)
|
||||
autoScan: GLOBAL_KEY, // 是否自动识别文本节点
|
||||
hasRichText: GLOBAL_KEY, // 是否启用富文本翻译
|
||||
hasShadowroot: GLOBAL_KEY, // 是否包含shadowroot
|
||||
rootsSelector: "", // 翻译范围选择器
|
||||
ignoreSelector: "", // 不翻译的选择器
|
||||
};
|
||||
|
||||
// 全局规则
|
||||
@@ -99,7 +107,7 @@ export const GLOBLA_RULE = {
|
||||
translator: OPT_TRANS_MICROSOFT, // 翻译服务
|
||||
fromLang: "auto", // 源语言
|
||||
toLang: "zh-CN", // 目标语言
|
||||
textStyle: OPT_STYLE_DASHLINE, // 译文样式
|
||||
textStyle: OPT_STYLE_NONE, // 译文样式
|
||||
transOpen: "false", // 开启翻译
|
||||
bgColor: "", // 译文颜色
|
||||
textDiyStyle: "", // 自定义译文样式
|
||||
@@ -108,17 +116,22 @@ export const GLOBLA_RULE = {
|
||||
injectJs: "", // 注入JS
|
||||
injectCss: "", // 注入CSS
|
||||
transOnly: "false", // 是否仅显示译文
|
||||
transTiming: OPT_TIMING_PAGESCROLL, // 翻译时机/鼠标悬停翻译
|
||||
// transTiming: OPT_TIMING_PAGESCROLL, // 翻译时机/鼠标悬停翻译 (暂时作废)
|
||||
transTag: DEFAULT_TRANS_TAG, // 译文元素标签
|
||||
transTitle: "false", // 是否同时翻译页面标题
|
||||
transSelected: "true", // 是否启用划词翻译
|
||||
detectRemote: "false", // 是否使用远程语言检测
|
||||
skipLangs: [], // 不翻译的语言
|
||||
fixerSelector: "", // 修复函数选择器
|
||||
fixerFunc: "-", // 修复函数
|
||||
// fixerSelector: "", // 修复函数选择器 (暂时作废)
|
||||
// fixerFunc: "-", // 修复函数 (暂时作废)
|
||||
transStartHook: "", // 钩子函数
|
||||
transEndHook: "", // 钩子函数
|
||||
transRemoveHook: "", // 钩子函数
|
||||
// transRemoveHook: "", // 钩子函数 (暂时作废)
|
||||
autoScan: "true", // 是否自动识别文本节点
|
||||
hasRichText: "true", // 是否启用富文本翻译
|
||||
hasShadowroot: "false", // 是否包含shadowroot
|
||||
rootsSelector: "body", // 翻译范围选择器
|
||||
ignoreSelector: DEFAULT_IGNORE_SELECTOR, // 不翻译的选择器
|
||||
};
|
||||
|
||||
export const DEFAULT_RULES = [GLOBLA_RULE];
|
||||
|
||||
@@ -18,8 +18,8 @@ export const DEFAULT_SHORTCUTS = {
|
||||
[OPT_SHORTCUT_SETTING]: ["AltLeft", "KeyO"],
|
||||
};
|
||||
|
||||
export const TRANS_MIN_LENGTH = 5; // 最短翻译长度
|
||||
export const TRANS_MAX_LENGTH = 10000; // 最长翻译长度
|
||||
export const TRANS_MIN_LENGTH = 2; // 最短翻译长度
|
||||
export const TRANS_MAX_LENGTH = 100000; // 最长翻译长度
|
||||
export const TRANS_NEWLINE_LENGTH = 20; // 换行字符数
|
||||
export const DEFAULT_BLACKLIST = [
|
||||
"https://fishjar.github.io/kiss-translator/options.html",
|
||||
@@ -108,6 +108,12 @@ export const DEFAULT_SUBRULES_LIST = [
|
||||
},
|
||||
];
|
||||
|
||||
export const DEFAULT__MOUSEHOVER_KEY = ["ControlLeft"];
|
||||
export const DEFAULT_MOUSE_HOVER_SETTING = {
|
||||
useMouseHover: true, // 是否启用鼠标悬停翻译
|
||||
mouseHoverKey: DEFAULT__MOUSEHOVER_KEY, // 鼠标悬停翻译组合键
|
||||
};
|
||||
|
||||
export const DEFAULT_SETTING = {
|
||||
darkMode: false, // 深色模式
|
||||
uiLang: "en", // 界面语言
|
||||
@@ -137,6 +143,7 @@ export const DEFAULT_SETTING = {
|
||||
blacklist: DEFAULT_BLACKLIST.join(",\n"), // 禁用翻译名单
|
||||
csplist: DEFAULT_CSPLIST.join(",\n"), // 禁用CSP名单
|
||||
// disableLangs: [], // 不翻译的语言(移至rule,作废)
|
||||
transInterval: 500, // 翻译间隔时间
|
||||
transInterval: 200, // 翻译等待时间
|
||||
langDetector: OPT_TRANS_MICROSOFT, // 远程语言识别服务
|
||||
mouseHoverSetting: DEFAULT_MOUSE_HOVER_SETTING, // 鼠标悬停翻译
|
||||
};
|
||||
|
||||
19
src/hooks/MouseHover.js
Normal file
19
src/hooks/MouseHover.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import { useCallback } from "react";
|
||||
import { DEFAULT_MOUSE_HOVER_SETTING } from "../config";
|
||||
import { useSetting } from "./Setting";
|
||||
|
||||
export function useMouseHoverSetting() {
|
||||
const { setting, updateSetting } = useSetting();
|
||||
const mouseHoverSetting =
|
||||
setting?.mouseHoverSetting || DEFAULT_MOUSE_HOVER_SETTING;
|
||||
|
||||
const updateMouseHoverSetting = useCallback(
|
||||
async (obj) => {
|
||||
Object.assign(mouseHoverSetting, obj);
|
||||
await updateSetting({ mouseHoverSetting });
|
||||
},
|
||||
[mouseHoverSetting, updateSetting]
|
||||
);
|
||||
|
||||
return { mouseHoverSetting, updateMouseHoverSetting };
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Function to inject inline JavaScript code
|
||||
export const injectInlineJs = (code) => {
|
||||
const el = document.createElement("script");
|
||||
el.setAttribute("data-source", "KISS-Calendar injectInlineJs");
|
||||
el.setAttribute("data-source", "kiss-inject injectInlineJs");
|
||||
el.setAttribute("type", "text/javascript");
|
||||
el.textContent = code;
|
||||
document.body?.appendChild(el);
|
||||
@@ -10,7 +10,7 @@ export const injectInlineJs = (code) => {
|
||||
// Function to inject external JavaScript file
|
||||
export const injectExternalJs = (src) => {
|
||||
const el = document.createElement("script");
|
||||
el.setAttribute("data-source", "KISS-Calendar injectExternalJs");
|
||||
el.setAttribute("data-source", "kiss-inject injectExternalJs");
|
||||
el.setAttribute("type", "text/javascript");
|
||||
el.setAttribute("src", src);
|
||||
document.body?.appendChild(el);
|
||||
@@ -19,7 +19,7 @@ export const injectExternalJs = (src) => {
|
||||
// Function to inject internal CSS code
|
||||
export const injectInternalCss = (styles) => {
|
||||
const el = document.createElement("style");
|
||||
el.setAttribute("data-source", "KISS-Calendar injectInternalCss");
|
||||
el.setAttribute("data-source", "kiss-inject injectInternalCss");
|
||||
el.textContent = styles;
|
||||
document.head?.appendChild(el);
|
||||
};
|
||||
@@ -27,7 +27,7 @@ export const injectInternalCss = (styles) => {
|
||||
// Function to inject external CSS file
|
||||
export const injectExternalCss = (href) => {
|
||||
const el = document.createElement("link");
|
||||
el.setAttribute("data-source", "KISS-Calendar injectExternalCss");
|
||||
el.setAttribute("data-source", "kiss-inject injectExternalCss");
|
||||
el.setAttribute("rel", "stylesheet");
|
||||
el.setAttribute("type", "text/css");
|
||||
el.setAttribute("href", href);
|
||||
|
||||
@@ -6,13 +6,13 @@ import {
|
||||
OPT_STYLE_ALL,
|
||||
OPT_LANGS_FROM,
|
||||
OPT_LANGS_TO,
|
||||
OPT_TIMING_ALL,
|
||||
// OPT_TIMING_ALL,
|
||||
GLOBLA_RULE,
|
||||
} from "../config";
|
||||
import { loadOrFetchSubRules } from "./subRules";
|
||||
import { getRulesWithDefault, setRules } from "./storage";
|
||||
import { trySyncRules } from "./sync";
|
||||
import { FIXER_ALL } from "./webfix";
|
||||
// import { FIXER_ALL } from "./webfix";
|
||||
import { kissLog } from "./log";
|
||||
|
||||
/**
|
||||
@@ -68,15 +68,17 @@ export const matchRule = async (
|
||||
[
|
||||
"selector",
|
||||
"keepSelector",
|
||||
"rootsSelector",
|
||||
"ignoreSelector",
|
||||
"terms",
|
||||
"selectStyle",
|
||||
"parentStyle",
|
||||
"injectJs",
|
||||
"injectCss",
|
||||
"fixerSelector",
|
||||
// "fixerSelector",
|
||||
"transStartHook",
|
||||
"transEndHook",
|
||||
"transRemoveHook",
|
||||
// "transRemoveHook",
|
||||
].forEach((key) => {
|
||||
if (!rule[key]?.trim()) {
|
||||
rule[key] = globalRule[key];
|
||||
@@ -89,12 +91,15 @@ export const matchRule = async (
|
||||
"toLang",
|
||||
"transOpen",
|
||||
"transOnly",
|
||||
"transTiming",
|
||||
// "transTiming",
|
||||
"autoScan",
|
||||
"hasRichText",
|
||||
"hasShadowroot",
|
||||
"transTag",
|
||||
"transTitle",
|
||||
"transSelected",
|
||||
"detectRemote",
|
||||
"fixerFunc",
|
||||
// "fixerFunc",
|
||||
].forEach((key) => {
|
||||
if (rule[key] === undefined || rule[key] === GLOBAL_KEY) {
|
||||
rule[key] = globalRule[key];
|
||||
@@ -146,6 +151,8 @@ export const checkRules = (rules) => {
|
||||
pattern,
|
||||
selector,
|
||||
keepSelector,
|
||||
rootsSelector,
|
||||
ignoreSelector,
|
||||
terms,
|
||||
selectStyle,
|
||||
parentStyle,
|
||||
@@ -159,21 +166,26 @@ export const checkRules = (rules) => {
|
||||
bgColor,
|
||||
textDiyStyle,
|
||||
transOnly,
|
||||
transTiming,
|
||||
autoScan,
|
||||
hasRichText,
|
||||
hasShadowroot,
|
||||
// transTiming,
|
||||
transTag,
|
||||
transTitle,
|
||||
transSelected,
|
||||
detectRemote,
|
||||
skipLangs,
|
||||
fixerSelector,
|
||||
fixerFunc,
|
||||
// fixerSelector,
|
||||
// fixerFunc,
|
||||
transStartHook,
|
||||
transEndHook,
|
||||
transRemoveHook,
|
||||
// transRemoveHook,
|
||||
}) => ({
|
||||
pattern: pattern.trim(),
|
||||
selector: type(selector) === "string" ? selector : "",
|
||||
keepSelector: type(keepSelector) === "string" ? keepSelector : "",
|
||||
rootsSelector: type(rootsSelector) === "string" ? rootsSelector : "",
|
||||
ignoreSelector: type(ignoreSelector) === "string" ? ignoreSelector : "",
|
||||
terms: type(terms) === "string" ? terms : "",
|
||||
selectStyle: type(selectStyle) === "string" ? selectStyle : "",
|
||||
parentStyle: type(parentStyle) === "string" ? parentStyle : "",
|
||||
@@ -187,18 +199,21 @@ export const checkRules = (rules) => {
|
||||
textStyle: matchValue([GLOBAL_KEY, ...OPT_STYLE_ALL], textStyle),
|
||||
transOpen: matchValue([GLOBAL_KEY, "true", "false"], transOpen),
|
||||
transOnly: matchValue([GLOBAL_KEY, "true", "false"], transOnly),
|
||||
transTiming: matchValue([GLOBAL_KEY, ...OPT_TIMING_ALL], transTiming),
|
||||
autoScan: matchValue([GLOBAL_KEY, "true", "false"], autoScan),
|
||||
hasRichText: matchValue([GLOBAL_KEY, "true", "false"], hasRichText),
|
||||
hasShadowroot: matchValue([GLOBAL_KEY, "true", "false"], hasShadowroot),
|
||||
// transTiming: matchValue([GLOBAL_KEY, ...OPT_TIMING_ALL], transTiming),
|
||||
transTag: matchValue([GLOBAL_KEY, "span", "font"], transTag),
|
||||
transTitle: matchValue([GLOBAL_KEY, "true", "false"], transTitle),
|
||||
transSelected: matchValue([GLOBAL_KEY, "true", "false"], transSelected),
|
||||
detectRemote: matchValue([GLOBAL_KEY, "true", "false"], detectRemote),
|
||||
skipLangs: type(skipLangs) === "array" ? skipLangs : [],
|
||||
fixerSelector: type(fixerSelector) === "string" ? fixerSelector : "",
|
||||
// fixerSelector: type(fixerSelector) === "string" ? fixerSelector : "",
|
||||
transStartHook: type(transStartHook) === "string" ? transStartHook : "",
|
||||
transEndHook: type(transEndHook) === "string" ? transEndHook : "",
|
||||
transRemoveHook:
|
||||
type(transRemoveHook) === "string" ? transRemoveHook : "",
|
||||
fixerFunc: matchValue([GLOBAL_KEY, ...FIXER_ALL], fixerFunc),
|
||||
// transRemoveHook:
|
||||
// type(transRemoveHook) === "string" ? transRemoveHook : "",
|
||||
// fixerFunc: matchValue([GLOBAL_KEY, ...FIXER_ALL], fixerFunc),
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
56
src/libs/shadowroot.js
Normal file
56
src/libs/shadowroot.js
Normal file
@@ -0,0 +1,56 @@
|
||||
import { kissLog } from "./log";
|
||||
|
||||
/**
|
||||
* @class ShadowRootMonitor
|
||||
* @description 通过覆写 Element.prototype.attachShadow 来监控页面上所有新创建的 Shadow DOM
|
||||
*/
|
||||
export class ShadowRootMonitor {
|
||||
/**
|
||||
* @param {function(ShadowRoot): void} callback - 当一个新的 shadowRoot 被创建时调用的回调函数。
|
||||
*/
|
||||
constructor(callback) {
|
||||
if (typeof callback !== "function") {
|
||||
throw new Error("Callback must be a function.");
|
||||
}
|
||||
|
||||
this.callback = callback;
|
||||
this.isMonitoring = false;
|
||||
this.originalAttachShadow = Element.prototype.attachShadow;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始监控 shadowRoot 的创建。
|
||||
*/
|
||||
start() {
|
||||
if (this.isMonitoring) {
|
||||
return;
|
||||
}
|
||||
const monitorInstance = this;
|
||||
|
||||
Element.prototype.attachShadow = function (...args) {
|
||||
const shadowRoot = monitorInstance.originalAttachShadow.apply(this, args);
|
||||
if (shadowRoot) {
|
||||
try {
|
||||
monitorInstance.callback(shadowRoot);
|
||||
} catch (error) {
|
||||
kissLog(error, "Error in ShadowRootMonitor callback");
|
||||
}
|
||||
}
|
||||
return shadowRoot;
|
||||
};
|
||||
|
||||
this.isMonitoring = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止监控,并恢复原始的 attachShadow 方法。
|
||||
*/
|
||||
stop() {
|
||||
if (!this.isMonitoring) {
|
||||
return;
|
||||
}
|
||||
|
||||
Element.prototype.attachShadow = this.originalAttachShadow;
|
||||
this.isMonitoring = false;
|
||||
}
|
||||
}
|
||||
102
src/libs/style.js
Normal file
102
src/libs/style.js
Normal file
@@ -0,0 +1,102 @@
|
||||
import { css } from "@emotion/css";
|
||||
import {
|
||||
OPT_STYLE_NONE,
|
||||
OPT_STYLE_LINE,
|
||||
OPT_STYLE_DOTLINE,
|
||||
OPT_STYLE_DASHLINE,
|
||||
OPT_STYLE_WAVYLINE,
|
||||
OPT_STYLE_DASHBOX,
|
||||
OPT_STYLE_FUZZY,
|
||||
OPT_STYLE_HIGHLIGHT,
|
||||
OPT_STYLE_BLOCKQUOTE,
|
||||
OPT_STYLE_DIY,
|
||||
DEFAULT_COLOR,
|
||||
} from "../config";
|
||||
|
||||
const genLineStyle = (style, color) => `
|
||||
opacity: 0.6;
|
||||
-webkit-opacity: 0.6;
|
||||
text-decoration-line: underline;
|
||||
text-decoration-style: ${style};
|
||||
text-decoration-color: ${color};
|
||||
text-decoration-thickness: 2px;
|
||||
text-underline-offset: 0.3em;
|
||||
-webkit-text-decoration-line: underline;
|
||||
-webkit-text-decoration-style: ${style};
|
||||
-webkit-text-decoration-color: ${color};
|
||||
-webkit-text-decoration-thickness: 2px;
|
||||
-webkit-text-underline-offset: 0.3em;
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
-webkit-opacity: 1;
|
||||
}
|
||||
`;
|
||||
|
||||
const genStyles = ({ textDiyStyle, bgColor = DEFAULT_COLOR }) => ({
|
||||
// 无样式
|
||||
[OPT_STYLE_NONE]: ``,
|
||||
// 下划线
|
||||
[OPT_STYLE_LINE]: genLineStyle("solid", bgColor),
|
||||
// 点状线
|
||||
[OPT_STYLE_DOTLINE]: genLineStyle("dotted", bgColor),
|
||||
// 虚线
|
||||
[OPT_STYLE_DASHLINE]: genLineStyle("dashed", bgColor),
|
||||
// 波浪线
|
||||
[OPT_STYLE_WAVYLINE]: genLineStyle("wavy", bgColor),
|
||||
// 虚线框
|
||||
[OPT_STYLE_DASHBOX]: `
|
||||
color: ${bgColor || DEFAULT_COLOR};
|
||||
border: 1px dashed ${bgColor || DEFAULT_COLOR};
|
||||
background: transparent;
|
||||
display: block;
|
||||
padding: 0.2em 0.5em;
|
||||
box-sizing: border-box;
|
||||
`,
|
||||
// 模糊
|
||||
[OPT_STYLE_FUZZY]: `
|
||||
filter: blur(0.2em);
|
||||
-webkit-filter: blur(0.2em);
|
||||
&:hover {
|
||||
filter: none;
|
||||
-webkit-filter: none;
|
||||
}
|
||||
`,
|
||||
// 高亮
|
||||
[OPT_STYLE_HIGHLIGHT]: `
|
||||
color: #fff;
|
||||
background-color: ${bgColor || DEFAULT_COLOR};
|
||||
`,
|
||||
// 引用
|
||||
[OPT_STYLE_BLOCKQUOTE]: `
|
||||
opacity: 0.6;
|
||||
-webkit-opacity: 0.6;
|
||||
display: block;
|
||||
padding: 0 0.75em;
|
||||
border-left: 0.25em solid ${bgColor || DEFAULT_COLOR};
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
-webkit-opacity: 1;
|
||||
}
|
||||
`,
|
||||
// 自定义
|
||||
[OPT_STYLE_DIY]: textDiyStyle,
|
||||
});
|
||||
|
||||
export const genTextClass = ({ textDiyStyle, bgColor = DEFAULT_COLOR }) => {
|
||||
const styles = genStyles({ textDiyStyle, bgColor });
|
||||
const textClass = {};
|
||||
let textStyles = "";
|
||||
Object.entries(styles).forEach(([k, v]) => {
|
||||
textClass[k] = css`
|
||||
${v}
|
||||
`;
|
||||
});
|
||||
Object.entries(styles).forEach(([k, v]) => {
|
||||
textStyles += `
|
||||
.${textClass[k]} {
|
||||
${v}
|
||||
}
|
||||
`;
|
||||
});
|
||||
return [textClass, textStyles];
|
||||
};
|
||||
@@ -1,34 +1,14 @@
|
||||
export const loadingSvg = `
|
||||
<svg viewBox="0 0 100 100" style="display:inline-block; width:100%; height: 100%; max-width: 24; max-height: 24;">
|
||||
<circle fill="#209CEE" stroke="none" cx="6" cy="50" r="6">
|
||||
<animateTransform
|
||||
attributeName="transform"
|
||||
dur="1s"
|
||||
type="translate"
|
||||
values="0 15 ; 0 -15; 0 15"
|
||||
repeatCount="indefinite"
|
||||
begin="0.1"
|
||||
/>
|
||||
</circle>
|
||||
<circle fill="#209CEE" stroke="none" cx="30" cy="50" r="6">
|
||||
<animateTransform
|
||||
attributeName="transform"
|
||||
dur="1s"
|
||||
type="translate"
|
||||
values="0 10 ; 0 -10; 0 10"
|
||||
repeatCount="indefinite"
|
||||
begin="0.2"
|
||||
/>
|
||||
</circle>
|
||||
<circle fill="#209CEE" stroke="none" cx="54" cy="50" r="6">
|
||||
<animateTransform
|
||||
attributeName="transform"
|
||||
dur="1s"
|
||||
type="translate"
|
||||
values="0 5 ; 0 -5; 0 5"
|
||||
repeatCount="indefinite"
|
||||
begin="0.3"
|
||||
/>
|
||||
</circle>
|
||||
<svg viewBox="0 0 100 100"
|
||||
style="display: inline-block; width: 1em; height: 1em; vertical-align: middle;">
|
||||
<circle fill="#209CEE" stroke="none" cx="6" cy="50" r="6">
|
||||
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 15 ; 0 -15; 0 15" repeatCount="indefinite" begin="0.1"/>
|
||||
</circle>
|
||||
<circle fill="#209CEE" stroke="none" cx="30" cy="50" r="6">
|
||||
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 10 ; 0 -10; 0 10" repeatCount="indefinite" begin="0.2"/>
|
||||
</circle>
|
||||
<circle fill="#209CEE" stroke="none" cx="54" cy="50" r="6">
|
||||
<animateTransform attributeName="transform" dur="1s" type="translate" values="0 5 ; 0 -5; 0 5" repeatCount="indefinite" begin="0.3"/>
|
||||
</circle>
|
||||
</svg>
|
||||
`;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -177,7 +177,7 @@ export const sha256 = async (text, salt) => {
|
||||
* 生成随机事件名称
|
||||
* @returns
|
||||
*/
|
||||
export const genEventName = () => btoa(Math.random()).slice(3, 11);
|
||||
export const genEventName = () => `kiss-${btoa(Math.random()).slice(3, 11)}`;
|
||||
|
||||
/**
|
||||
* 判断两个 Set 是否相同
|
||||
@@ -302,3 +302,16 @@ export const extractJson = (raw) => {
|
||||
const match = s.match(/\{[\s\S]*\}/);
|
||||
return match ? match[0] : "{}";
|
||||
};
|
||||
|
||||
/**
|
||||
* 空闲执行
|
||||
* @param {*} cb
|
||||
* @param {*} timeout
|
||||
* @returns
|
||||
*/
|
||||
export const scheduleIdle = (cb, timeout = 200) => {
|
||||
if (window.requestIdleCallback) {
|
||||
return requestIdleCallback(cb, { timeout });
|
||||
}
|
||||
return setTimeout(cb, timeout);
|
||||
};
|
||||
|
||||
@@ -560,7 +560,12 @@ function ApiAccordion({ translator }) {
|
||||
return (
|
||||
<Accordion expanded={expanded} onChange={handleChange}>
|
||||
<AccordionSummary expandIcon={<ExpandMoreIcon />}>
|
||||
<Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
opacity: api.isDisabled ? 0.5 : 1,
|
||||
overflowWrap: "anywhere",
|
||||
}}
|
||||
>
|
||||
{api.apiName ? `${translator} (${api.apiName})` : translator}
|
||||
</Typography>
|
||||
</AccordionSummary>
|
||||
|
||||
57
src/views/Options/MouseHover.js
Normal file
57
src/views/Options/MouseHover.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import Box from "@mui/material/Box";
|
||||
import Stack from "@mui/material/Stack";
|
||||
import { useI18n } from "../../hooks/I18n";
|
||||
import ShortcutInput from "./ShortcutInput";
|
||||
import FormControlLabel from "@mui/material/FormControlLabel";
|
||||
import Switch from "@mui/material/Switch";
|
||||
import { useMouseHoverSetting } from "../../hooks/MouseHover";
|
||||
import { useCallback } from "react";
|
||||
import Grid from "@mui/material/Grid";
|
||||
|
||||
export default function MouseHoverSetting() {
|
||||
const i18n = useI18n();
|
||||
const { mouseHoverSetting, updateMouseHoverSetting } = useMouseHoverSetting();
|
||||
|
||||
const handleShortcutInput = useCallback(
|
||||
(val) => {
|
||||
updateMouseHoverSetting({ mouseHoverKey: val });
|
||||
},
|
||||
[updateMouseHoverSetting]
|
||||
);
|
||||
|
||||
const { useMouseHover = true, mouseHoverKey = ["ControlLeft"] } =
|
||||
mouseHoverSetting;
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Stack spacing={3}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
size="small"
|
||||
name="useMouseHover"
|
||||
checked={useMouseHover}
|
||||
onChange={() => {
|
||||
updateMouseHoverSetting({ useMouseHover: !useMouseHover });
|
||||
}}
|
||||
/>
|
||||
}
|
||||
label={i18n("use_mousehover_translation")}
|
||||
/>
|
||||
|
||||
<Box>
|
||||
<Grid container spacing={2} columns={12}>
|
||||
<Grid item xs={12} sm={12} md={4} lg={4}>
|
||||
<ShortcutInput
|
||||
value={mouseHoverKey}
|
||||
onChange={handleShortcutInput}
|
||||
label={i18n("trigger_trans_shortcut")}
|
||||
helperText={i18n("mousehover_key_help")}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import ApiIcon from "@mui/icons-material/Api";
|
||||
import InputIcon from "@mui/icons-material/Input";
|
||||
import SelectAllIcon from "@mui/icons-material/SelectAll";
|
||||
import EventNoteIcon from "@mui/icons-material/EventNote";
|
||||
import MouseIcon from '@mui/icons-material/Mouse';
|
||||
|
||||
function LinkItem({ label, url, icon }) {
|
||||
const match = useMatch(url);
|
||||
@@ -52,6 +53,12 @@ export default function Navigator(props) {
|
||||
url: "/tranbox",
|
||||
icon: <SelectAllIcon />,
|
||||
},
|
||||
{
|
||||
id: "mousehover_translate",
|
||||
label: i18n("mousehover_translate"),
|
||||
url: "/mousehover",
|
||||
icon: <MouseIcon />,
|
||||
},
|
||||
{
|
||||
id: "apis_setting",
|
||||
label: i18n("apis_setting"),
|
||||
|
||||
@@ -16,9 +16,7 @@ import {
|
||||
OPT_STYLE_USE_COLOR,
|
||||
URL_KISS_RULES_NEW_ISSUE,
|
||||
OPT_SYNCTYPE_WORKER,
|
||||
OPT_TIMING_PAGESCROLL,
|
||||
DEFAULT_TRANS_TAG,
|
||||
OPT_TIMING_ALL,
|
||||
} from "../../config";
|
||||
import { useState, useEffect, useMemo } from "react";
|
||||
import { useI18n } from "../../hooks/I18n";
|
||||
@@ -55,7 +53,6 @@ import HelpButton from "./HelpButton";
|
||||
import { useSyncCaches } from "../../hooks/Sync";
|
||||
import DownloadButton from "./DownloadButton";
|
||||
import UploadButton from "./UploadButton";
|
||||
import { FIXER_ALL } from "../../libs/webfix";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import CancelIcon from "@mui/icons-material/Cancel";
|
||||
@@ -78,6 +75,8 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
||||
pattern,
|
||||
selector,
|
||||
keepSelector = "",
|
||||
rootsSelector = "",
|
||||
ignoreSelector = "",
|
||||
terms = "",
|
||||
selectStyle = "",
|
||||
parentStyle = "",
|
||||
@@ -91,17 +90,20 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
||||
bgColor,
|
||||
textDiyStyle,
|
||||
transOnly = "false",
|
||||
transTiming = OPT_TIMING_PAGESCROLL,
|
||||
autoScan = "true",
|
||||
hasRichText = "true",
|
||||
hasShadowroot = "false",
|
||||
// transTiming = OPT_TIMING_PAGESCROLL,
|
||||
transTag = DEFAULT_TRANS_TAG,
|
||||
transTitle = "false",
|
||||
transSelected = "true",
|
||||
detectRemote = "false",
|
||||
skipLangs = [],
|
||||
fixerSelector = "",
|
||||
fixerFunc = "-",
|
||||
// fixerSelector = "",
|
||||
// fixerFunc = "-",
|
||||
transStartHook = "",
|
||||
transEndHook = "",
|
||||
transRemoveHook = "",
|
||||
// transRemoveHook = "",
|
||||
} = formValues;
|
||||
|
||||
const hasSamePattern = (str) => {
|
||||
@@ -236,7 +238,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
||||
helperText={errors.selector || i18n("selector_helper")}
|
||||
name="selector"
|
||||
value={selector}
|
||||
disabled={disabled}
|
||||
disabled={autoScan === "true" || disabled}
|
||||
onChange={handleChange}
|
||||
onFocus={handleFocus}
|
||||
multiline
|
||||
@@ -251,6 +253,26 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
||||
onChange={handleChange}
|
||||
multiline
|
||||
/>
|
||||
<TextField
|
||||
size="small"
|
||||
label={i18n("root_selector")}
|
||||
helperText={i18n("root_selector_helper")}
|
||||
name="rootsSelector"
|
||||
value={rootsSelector}
|
||||
disabled={disabled}
|
||||
onChange={handleChange}
|
||||
multiline
|
||||
/>
|
||||
<TextField
|
||||
size="small"
|
||||
label={i18n("ignore_selector")}
|
||||
helperText={i18n("ignore_selector_helper")}
|
||||
name="ignoreSelector"
|
||||
value={ignoreSelector}
|
||||
disabled={disabled}
|
||||
onChange={handleChange}
|
||||
multiline
|
||||
/>
|
||||
|
||||
<Box>
|
||||
<Grid container spacing={2} columns={12}>
|
||||
@@ -270,6 +292,126 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
||||
<MenuItem value={"false"}>{i18n("default_disabled")}</MenuItem>
|
||||
</TextField>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={3} lg={2}>
|
||||
<TextField
|
||||
select
|
||||
size="small"
|
||||
fullWidth
|
||||
name="autoScan"
|
||||
value={autoScan}
|
||||
label={i18n("auto_scan_page")}
|
||||
disabled={disabled}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{GlobalItem}
|
||||
<MenuItem value={"false"}>{i18n("disable")}</MenuItem>
|
||||
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
||||
</TextField>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={3} lg={2}>
|
||||
<TextField
|
||||
select
|
||||
size="small"
|
||||
fullWidth
|
||||
name="hasRichText"
|
||||
value={hasRichText}
|
||||
label={i18n("has_rich_text")}
|
||||
disabled={disabled}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{GlobalItem}
|
||||
<MenuItem value={"false"}>{i18n("disable")}</MenuItem>
|
||||
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
||||
</TextField>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={3} lg={2}>
|
||||
<TextField
|
||||
select
|
||||
size="small"
|
||||
fullWidth
|
||||
name="hasShadowroot"
|
||||
value={hasShadowroot}
|
||||
label={i18n("has_shadowroot")}
|
||||
disabled={disabled}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{GlobalItem}
|
||||
<MenuItem value={"false"}>{i18n("disable")}</MenuItem>
|
||||
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
||||
</TextField>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={3} lg={2}>
|
||||
<TextField
|
||||
select
|
||||
size="small"
|
||||
fullWidth
|
||||
name="transSelected"
|
||||
value={transSelected}
|
||||
label={i18n("translate_selected")}
|
||||
disabled={disabled}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{GlobalItem}
|
||||
<MenuItem value={"false"}>{i18n("disable")}</MenuItem>
|
||||
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
||||
</TextField>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={3} lg={2}>
|
||||
<TextField
|
||||
select
|
||||
size="small"
|
||||
fullWidth
|
||||
name="transOnly"
|
||||
value={transOnly}
|
||||
label={i18n("show_only_translations")}
|
||||
disabled={disabled}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{GlobalItem}
|
||||
<MenuItem value={"false"}>{i18n("disable")}</MenuItem>
|
||||
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
||||
</TextField>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Grid container spacing={2} columns={12}>
|
||||
{/* <Grid item xs={12} sm={6} md={3} lg={2}>
|
||||
<TextField
|
||||
select
|
||||
size="small"
|
||||
fullWidth
|
||||
name="transTiming"
|
||||
value={transTiming}
|
||||
label={i18n("trigger_mode")}
|
||||
disabled={disabled}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{GlobalItem}
|
||||
{OPT_TIMING_ALL.map((item) => (
|
||||
<MenuItem key={item} value={item}>
|
||||
{i18n(item)}
|
||||
</MenuItem>
|
||||
))}
|
||||
</TextField>
|
||||
</Grid> */}
|
||||
<Grid item xs={12} sm={6} md={3} lg={2}>
|
||||
<TextField
|
||||
select
|
||||
size="small"
|
||||
fullWidth
|
||||
name="transTitle"
|
||||
value={transTitle}
|
||||
label={i18n("translate_page_title")}
|
||||
disabled={disabled}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{GlobalItem}
|
||||
<MenuItem value={"false"}>{i18n("disable")}</MenuItem>
|
||||
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
||||
</TextField>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={3} lg={2}>
|
||||
<TextField
|
||||
select
|
||||
@@ -378,41 +520,6 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
||||
|
||||
<Box>
|
||||
<Grid container spacing={2} columns={12}>
|
||||
<Grid item xs={12} sm={6} md={3} lg={2}>
|
||||
<TextField
|
||||
select
|
||||
size="small"
|
||||
fullWidth
|
||||
name="transOnly"
|
||||
value={transOnly}
|
||||
label={i18n("show_only_translations")}
|
||||
disabled={disabled}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{GlobalItem}
|
||||
<MenuItem value={"false"}>{i18n("disable")}</MenuItem>
|
||||
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
||||
</TextField>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={3} lg={2}>
|
||||
<TextField
|
||||
select
|
||||
size="small"
|
||||
fullWidth
|
||||
name="transTiming"
|
||||
value={transTiming}
|
||||
label={i18n("trigger_mode")}
|
||||
disabled={disabled}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{GlobalItem}
|
||||
{OPT_TIMING_ALL.map((item) => (
|
||||
<MenuItem key={item} value={item}>
|
||||
{i18n(item)}
|
||||
</MenuItem>
|
||||
))}
|
||||
</TextField>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={3} lg={2}>
|
||||
<TextField
|
||||
select
|
||||
@@ -429,38 +536,6 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
||||
<MenuItem value={"font"}>{`<font>`}</MenuItem>
|
||||
</TextField>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={3} lg={2}>
|
||||
<TextField
|
||||
select
|
||||
size="small"
|
||||
fullWidth
|
||||
name="transTitle"
|
||||
value={transTitle}
|
||||
label={i18n("translate_page_title")}
|
||||
disabled={disabled}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{GlobalItem}
|
||||
<MenuItem value={"false"}>{i18n("disable")}</MenuItem>
|
||||
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
||||
</TextField>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={3} lg={2}>
|
||||
<TextField
|
||||
select
|
||||
size="small"
|
||||
fullWidth
|
||||
name="transSelected"
|
||||
value={transSelected}
|
||||
label={i18n("translate_selected")}
|
||||
disabled={disabled}
|
||||
onChange={handleChange}
|
||||
>
|
||||
{GlobalItem}
|
||||
<MenuItem value={"false"}>{i18n("disable")}</MenuItem>
|
||||
<MenuItem value={"true"}>{i18n("enable")}</MenuItem>
|
||||
</TextField>
|
||||
</Grid>
|
||||
<Grid item xs={12} sm={6} md={3} lg={2}>
|
||||
<TextField
|
||||
select
|
||||
@@ -482,7 +557,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
||||
|
||||
{showMore && (
|
||||
<>
|
||||
<TextField
|
||||
{/* <TextField
|
||||
size="small"
|
||||
label={i18n("fixer_selector")}
|
||||
name="fixerSelector"
|
||||
@@ -508,7 +583,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
||||
{item}
|
||||
</MenuItem>
|
||||
))}
|
||||
</TextField>
|
||||
</TextField> */}
|
||||
|
||||
<TextField
|
||||
select
|
||||
@@ -542,40 +617,6 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
||||
maxRows={10}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
size="small"
|
||||
label={i18n("translate_start_hook")}
|
||||
helperText={i18n("translate_start_hook_helper")}
|
||||
name="transStartHook"
|
||||
value={transStartHook}
|
||||
disabled={disabled}
|
||||
onChange={handleChange}
|
||||
multiline
|
||||
maxRows={10}
|
||||
/>
|
||||
<TextField
|
||||
size="small"
|
||||
label={i18n("translate_end_hook")}
|
||||
helperText={i18n("translate_end_hook_helper")}
|
||||
name="transEndHook"
|
||||
value={transEndHook}
|
||||
disabled={disabled}
|
||||
onChange={handleChange}
|
||||
multiline
|
||||
maxRows={10}
|
||||
/>
|
||||
<TextField
|
||||
size="small"
|
||||
label={i18n("translate_remove_hook")}
|
||||
helperText={i18n("translate_remove_hook_helper")}
|
||||
name="transRemoveHook"
|
||||
value={transRemoveHook}
|
||||
disabled={disabled}
|
||||
onChange={handleChange}
|
||||
multiline
|
||||
maxRows={10}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
size="small"
|
||||
label={i18n("selector_style")}
|
||||
@@ -598,6 +639,41 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
||||
maxRows={10}
|
||||
multiline
|
||||
/>
|
||||
|
||||
<TextField
|
||||
size="small"
|
||||
label={i18n("translate_start_hook")}
|
||||
helperText={i18n("translate_start_hook_helper")}
|
||||
name="transStartHook"
|
||||
value={transStartHook}
|
||||
disabled={disabled}
|
||||
onChange={handleChange}
|
||||
multiline
|
||||
maxRows={10}
|
||||
/>
|
||||
<TextField
|
||||
size="small"
|
||||
label={i18n("translate_end_hook")}
|
||||
helperText={i18n("translate_end_hook_helper")}
|
||||
name="transEndHook"
|
||||
value={transEndHook}
|
||||
disabled={disabled}
|
||||
onChange={handleChange}
|
||||
multiline
|
||||
maxRows={10}
|
||||
/>
|
||||
{/* <TextField
|
||||
size="small"
|
||||
label={i18n("translate_remove_hook")}
|
||||
helperText={i18n("translate_remove_hook_helper")}
|
||||
name="transRemoveHook"
|
||||
value={transRemoveHook}
|
||||
disabled={disabled}
|
||||
onChange={handleChange}
|
||||
multiline
|
||||
maxRows={10}
|
||||
/> */}
|
||||
|
||||
<TextField
|
||||
size="small"
|
||||
label={i18n("inject_css")}
|
||||
|
||||
@@ -61,7 +61,7 @@ export default function Settings() {
|
||||
value = limitNumber(value, 0, 5000);
|
||||
break;
|
||||
case "transInterval":
|
||||
value = limitNumber(value, 100, 5000);
|
||||
value = limitNumber(value, 10, 2000);
|
||||
break;
|
||||
case "minLength":
|
||||
value = limitNumber(value, 1, 100);
|
||||
@@ -119,7 +119,7 @@ export default function Settings() {
|
||||
touchTranslate = 2,
|
||||
blacklist = DEFAULT_BLACKLIST.join(",\n"),
|
||||
csplist = DEFAULT_CSPLIST.join(",\n"),
|
||||
transInterval = 500,
|
||||
transInterval = 200,
|
||||
langDetector = OPT_TRANS_MICROSOFT,
|
||||
} = setting;
|
||||
const { isHide = false } = fab || {};
|
||||
|
||||
@@ -16,6 +16,7 @@ import { useCallback } from "react";
|
||||
import { limitNumber } from "../../libs/utils";
|
||||
import { useTranbox } from "../../hooks/Tranbox";
|
||||
import { isExt } from "../../libs/client";
|
||||
import Alert from "@mui/material/Alert";
|
||||
|
||||
export default function Tranbox() {
|
||||
const i18n = useI18n();
|
||||
@@ -67,6 +68,7 @@ export default function Tranbox() {
|
||||
return (
|
||||
<Box>
|
||||
<Stack spacing={3}>
|
||||
<Alert severity="info">{i18n("selected_translation_alert")}</Alert>
|
||||
<TextField
|
||||
select
|
||||
size="small"
|
||||
|
||||
@@ -21,6 +21,7 @@ import Apis from "./Apis";
|
||||
import InputSetting from "./InputSetting";
|
||||
import Tranbox from "./Tranbox";
|
||||
import FavWords from "./FavWords";
|
||||
import MouseHoverSetting from "./MouseHover";
|
||||
|
||||
export default function Options() {
|
||||
const [error, setError] = useState("");
|
||||
@@ -113,6 +114,7 @@ export default function Options() {
|
||||
<Route path="rules" element={<Rules />} />
|
||||
<Route path="input" element={<InputSetting />} />
|
||||
<Route path="tranbox" element={<Tranbox />} />
|
||||
<Route path="mousehover" element={<MouseHoverSetting />} />
|
||||
<Route path="apis" element={<Apis />} />
|
||||
<Route path="sync" element={<SyncSetting />} />
|
||||
<Route path="words" element={<FavWords />} />
|
||||
|
||||
@@ -5,6 +5,7 @@ import MenuItem from "@mui/material/MenuItem";
|
||||
import FormControlLabel from "@mui/material/FormControlLabel";
|
||||
import Switch from "@mui/material/Switch";
|
||||
import Button from "@mui/material/Button";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import { sendBgMsg, sendTabMsg, getCurTab } from "../../libs/msg";
|
||||
import { browser } from "../../libs/browser";
|
||||
import { isExt } from "../../libs/client";
|
||||
@@ -30,6 +31,8 @@ import { saveRule } from "../../libs/rules";
|
||||
import { tryClearCaches } from "../../libs";
|
||||
import { kissLog } from "../../libs/log";
|
||||
|
||||
// 插件popup没有参数
|
||||
// 网页弹框有
|
||||
export default function Popup({ setShowPopup, translator: tran }) {
|
||||
const i18n = useI18n();
|
||||
const [rule, setRule] = useState(tran?.rule);
|
||||
@@ -173,10 +176,20 @@ export default function Popup({ setShowPopup, translator: tran }) {
|
||||
);
|
||||
}
|
||||
|
||||
const { transOpen, translator, fromLang, toLang, textStyle } = rule;
|
||||
const {
|
||||
transOpen,
|
||||
translator,
|
||||
fromLang,
|
||||
toLang,
|
||||
textStyle,
|
||||
autoScan,
|
||||
transOnly,
|
||||
hasRichText,
|
||||
hasShadowroot,
|
||||
} = rule;
|
||||
|
||||
return (
|
||||
<Box minWidth={300}>
|
||||
<Box width={320}>
|
||||
{!tran && (
|
||||
<>
|
||||
<Header />
|
||||
@@ -184,26 +197,79 @@ export default function Popup({ setShowPopup, translator: tran }) {
|
||||
</>
|
||||
)}
|
||||
<Stack sx={{ p: 2 }} spacing={2}>
|
||||
<Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
spacing={2}
|
||||
>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={transOpen === "true"}
|
||||
onChange={handleTransToggle}
|
||||
/>
|
||||
}
|
||||
label={
|
||||
commands["toggleTranslate"]
|
||||
? `${i18n("translate_alt")}(${commands["toggleTranslate"]})`
|
||||
: i18n("translate_alt")
|
||||
}
|
||||
/>
|
||||
</Stack>
|
||||
<Grid container columns={12} spacing={1}>
|
||||
<Grid item xs={12}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={transOpen === "true"}
|
||||
onChange={handleTransToggle}
|
||||
/>
|
||||
}
|
||||
label={
|
||||
commands["toggleTranslate"]
|
||||
? `${i18n("translate_alt")}(${commands["toggleTranslate"]})`
|
||||
: i18n("translate_alt")
|
||||
}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
size="small"
|
||||
name="autoScan"
|
||||
value={autoScan === "true" ? "false" : "true"}
|
||||
checked={autoScan === "true"}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
}
|
||||
label={i18n("autoscan_alt")}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
size="small"
|
||||
name="hasShadowroot"
|
||||
value={hasShadowroot === "true" ? "false" : "true"}
|
||||
checked={hasShadowroot === "true"}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
}
|
||||
label={i18n("shadowroot_alt")}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
size="small"
|
||||
name="transOnly"
|
||||
value={transOnly === "true" ? "false" : "true"}
|
||||
checked={transOnly === "true"}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
}
|
||||
label={i18n("transonly_alt")}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={6}>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
size="small"
|
||||
name="hasRichText"
|
||||
value={hasRichText === "true" ? "false" : "true"}
|
||||
checked={hasRichText === "true"}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
}
|
||||
label={i18n("richtext_alt")}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<TextField
|
||||
select
|
||||
|
||||
Reference in New Issue
Block a user