Compare commits

...

20 Commits

Author SHA1 Message Date
Gabe Yuan
c1778fbcbb v1.6.11 2023-09-10 15:23:50 +08:00
Gabe Yuan
1ef9974c05 fix sync webfix 2023-09-10 15:04:41 +08:00
Gabe Yuan
399c6b6fed add global rule text 2023-09-10 14:51:16 +08:00
Gabe Yuan
62a60eee44 update help text 2023-09-10 14:34:55 +08:00
Gabe Yuan
54339af885 update readme 2023-09-10 14:19:31 +08:00
Gabe Yuan
06cfd33e60 add open options shortcut for ext 2023-09-10 13:56:11 +08:00
Gabe Yuan
08c9d78d2a add save rule button 2023-09-10 13:44:34 +08:00
Gabe Yuan
e7a5e5dce1 add save rule button 2023-09-10 13:09:19 +08:00
Gabe Yuan
3a59a127d1 add save rule button 2023-09-10 12:35:03 +08:00
Gabe Yuan
26f213cad2 add fontsize fixer 2023-09-09 23:32:17 +08:00
Gabe Yuan
7b6148302d v1.6.10 2023-09-09 20:15:09 +08:00
Gabe Yuan
38c781b8f3 fix open setting shortcut 2023-09-09 20:13:36 +08:00
Gabe Yuan
64d827fdcd v1.6.9 2023-09-09 19:51:32 +08:00
Gabe Yuan
74ad812f37 text opacity 2023-09-09 19:43:12 +08:00
Gabe Yuan
364c829119 fix sync bug 2023-09-09 19:26:22 +08:00
Gabe Yuan
1ac2c5b61e fix shortcut 2023-09-09 17:15:13 +08:00
Gabe Yuan
0766199353 check shortcut length 2023-09-09 15:26:05 +08:00
Gabe Yuan
878bccf151 hide fab & open setting shortcut 2023-09-09 15:08:34 +08:00
Gabe Yuan
acbd258296 shorten english tab name 2023-09-09 14:10:01 +08:00
Gabe Yuan
54a14e6e5a shortcut set blank 2023-09-09 14:05:45 +08:00
25 changed files with 250 additions and 100 deletions

2
.env
View File

@@ -2,7 +2,7 @@ GENERATE_SOURCEMAP=false
REACT_APP_NAME=KISS Translator
REACT_APP_NAME_CN=简约翻译
REACT_APP_VERSION=1.6.8
REACT_APP_VERSION=1.6.11
REACT_APP_HOMEPAGE=https://github.com/fishjar/kiss-translator

View File

@@ -44,7 +44,8 @@ If you also like a little more simplicity, welcome to pick it up.
- `Alt+Q` Toggle Translation
- `Alt+C` Toggle Styles
- `Alt+K` Open Menu
- `Alt+K` Open Popup
- `Alt+O` Open Options
## Schedule

View File

@@ -44,7 +44,8 @@
- `Alt+Q` 开启翻译
- `Alt+C` 切换样式
- `Alt+K` 打开菜单
- `Alt+K` 打开弹窗
- `Alt+O` 打开设置
## 进度

View File

@@ -1,7 +1,7 @@
{
"name": "kiss-translator",
"description": "A minimalist bilingual translation Extension & Greasemonkey Script",
"version": "1.6.8",
"version": "1.6.11",
"author": "Gabe<yugang2002@gmail.com>",
"private": true,
"dependencies": {

View File

@@ -10,5 +10,8 @@
},
"toggle_style": {
"message": "Toggle Style"
},
"open_options": {
"message": "Open Options"
}
}

View File

@@ -6,9 +6,12 @@
"message": "一个简约的双语网页翻译扩展 & 油猴脚本"
},
"toggle_translate": {
"message": "切换翻译"
"message": "开启翻译"
},
"toggle_style": {
"message": "切换样式"
},
"open_options": {
"message": "打开设置"
}
}

View File

@@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "__MSG_app_name__",
"description": "__MSG_app_description__",
"version": "1.6.8",
"version": "1.6.11",
"default_locale": "en",
"author": "Gabe<yugang2002@gmail.com>",
"homepage_url": "https://github.com/fishjar/kiss-translator",
@@ -33,6 +33,12 @@
"default": "Alt+C"
},
"description": "__MSG_toggle_style__"
},
"openOptions": {
"suggested_key": {
"default": "Alt+O"
},
"description": "__MSG_open_options__"
}
},
"permissions": ["<all_urls>", "storage"],

View File

@@ -2,7 +2,7 @@
"manifest_version": 3,
"name": "__MSG_app_name__",
"description": "__MSG_app_description__",
"version": "1.6.8",
"version": "1.6.11",
"default_locale": "en",
"author": "Gabe<yugang2002@gmail.com>",
"homepage_url": "https://github.com/fishjar/kiss-translator",
@@ -34,6 +34,12 @@
"default": "Alt+C"
},
"description": "__MSG_toggle_style__"
},
"openOptions": {
"suggested_key": {
"default": "Alt+O"
},
"description": "__MSG_open_options__"
}
},
"permissions": ["storage"],

View File

@@ -7,6 +7,7 @@ import {
MSG_TRANS_TOGGLE_STYLE,
CMD_TOGGLE_TRANSLATE,
CMD_TOGGLE_STYLE,
CMD_OPEN_OPTIONS,
} from "./config";
import { getSettingWithDefault, tryInitDefaultData } from "./libs/storage";
import { trySyncSettingAndRules } from "./libs/sync";
@@ -85,6 +86,9 @@ browser.commands.onCommand.addListener((command) => {
case CMD_TOGGLE_STYLE:
sendTabMsg(MSG_TRANS_TOGGLE_STYLE);
break;
case CMD_OPEN_OPTIONS:
browser.runtime.openOptionsPage();
break;
default:
}
});

View File

@@ -271,15 +271,15 @@ export const I18N = {
},
personal_rules: {
zh: `个人规则`,
en: `Personal Rules`,
en: `Rules`,
},
subscribe_rules: {
zh: `订阅规则`,
en: `Subscribe Rules`,
en: `Subscribe`,
},
overwrite_subscribe_rules: {
zh: `覆写订阅规则`,
en: `Overwrite Subscribe Rules`,
en: `Overwrite`,
},
subscribe_url: {
zh: `订阅地址`,
@@ -521,4 +521,28 @@ export const I18N = {
zh: `"打开弹窗"快捷键`,
en: `"Open Popup" Shortcut`,
},
open_setting_shortcut: {
zh: `"打开设置"快捷键`,
en: `"Open Setting" Shortcut`,
},
hide_fab_button: {
zh: `隐藏悬浮按钮`,
en: `"Hide Fab Button`,
},
show: {
zh: `显示`,
en: `"Show`,
},
hide: {
zh: `隐藏`,
en: `"Hide`,
},
save_rule: {
zh: `保存规则`,
en: `"Save Rule`,
},
global_rule: {
zh: `全局规则`,
en: `Global Rule`,
},
};

View File

@@ -29,6 +29,7 @@ export const STOKEY_WEBFIXCACHE_PREFIX = `${APP_NAME}_webfixcache_`;
export const CMD_TOGGLE_TRANSLATE = "toggleTranslate";
export const CMD_TOGGLE_STYLE = "toggleStyle";
export const CMD_OPEN_OPTIONS = "openOptions";
export const CLIENT_WEB = "web";
export const CLIENT_CHROME = "chrome";
@@ -243,10 +244,12 @@ export const DEFAULT_TRANS_APIS = {
export const OPT_SHORTCUT_TRANSLATE = "toggleTranslate";
export const OPT_SHORTCUT_STYLE = "toggleStyle";
export const OPT_SHORTCUT_POPUP = "togglePopup";
export const OPT_SHORTCUT_SETTING = "openSetting";
export const DEFAULT_SHORTCUTS = {
[OPT_SHORTCUT_TRANSLATE]: ["Alt", "q"],
[OPT_SHORTCUT_STYLE]: ["Alt", "c"],
[OPT_SHORTCUT_POPUP]: ["Alt", "k"],
[OPT_SHORTCUT_SETTING]: ["Alt", "o"],
};
export const TRANS_MIN_LENGTH = 5; // 最短翻译长度
@@ -269,6 +272,7 @@ export const DEFAULT_SETTING = {
transApis: DEFAULT_TRANS_APIS, // 翻译接口
mouseKey: OPT_MOUSEKEY_DISABLE, // 鼠标悬停翻译
shortcuts: DEFAULT_SHORTCUTS, // 快捷键
hideFab: false, // 是否隐藏按钮
};
export const DEFAULT_RULES = [GLOBLA_RULE];

View File

@@ -1,7 +1,6 @@
import { STOKEY_RULES, DEFAULT_RULES } from "../config";
import { useStorage } from "./Storage";
import { trySyncRules } from "../libs/sync";
import { useSync } from "./Sync";
import { checkRules } from "../libs/rules";
import { useCallback } from "react";
@@ -11,19 +10,13 @@ import { useCallback } from "react";
*/
export function useRules() {
const { data: list, save } = useStorage(STOKEY_RULES, DEFAULT_RULES);
const {
sync: { rulesUpdateAt },
updateSync,
} = useSync();
const updateRules = useCallback(
async (rules) => {
const updateAt = rulesUpdateAt ? Date.now() : 0;
await save(rules);
await updateSync({ rulesUpdateAt: updateAt });
trySyncRules();
},
[rulesUpdateAt, save, updateSync]
[save]
);
const add = useCallback(

View File

@@ -1,6 +1,5 @@
import { STOKEY_SETTING, DEFAULT_SETTING } from "../config";
import { useStorage } from "./Storage";
import { useSync } from "./Sync";
import { trySyncSetting } from "../libs/sync";
import { createContext, useCallback, useContext, useMemo } from "react";
import { debounce } from "../libs/utils";
@@ -16,10 +15,6 @@ export function SettingProvider({ children }) {
STOKEY_SETTING,
DEFAULT_SETTING
);
const {
sync: { settingUpdateAt },
updateSync,
} = useSync();
const syncSetting = useMemo(
() =>
@@ -31,12 +26,10 @@ export function SettingProvider({ children }) {
const updateSetting = useCallback(
async (obj) => {
const updateAt = settingUpdateAt ? Date.now() : 0;
await update(obj);
await updateSync({ settingUpdateAt: updateAt });
syncSetting();
},
[settingUpdateAt, update, updateSync, syncSetting]
[update, syncSetting]
);
if (loading) {

View File

@@ -5,6 +5,7 @@ import { useSetting } from "./Setting";
export function useShortcut(action) {
const { setting, updateSetting } = useSetting();
const shortcuts = setting?.shortcuts || DEFAULT_SHORTCUTS;
const shortcut = shortcuts[action] || [];
const setShortcut = useCallback(
async (val) => {
@@ -14,5 +15,5 @@ export function useShortcut(action) {
[action, shortcuts, updateSetting]
);
return { shortcut: shortcuts[action] || [], setShortcut };
return { shortcut, setShortcut };
}

View File

@@ -19,3 +19,12 @@ export const sendTabMsg = async (action, args) => {
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
return browser.tabs.sendMessage(tabs[0].id, { action, args });
};
/**
* 获取当前tab信息
* @returns
*/
export const getTabInfo = async () => {
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
return tabs[0];
};

View File

@@ -11,6 +11,8 @@ import {
DEFAULT_OW_RULE,
} from "../config";
import { loadOrFetchSubRules } from "./subRules";
import { getRulesWithDefault, setRules } from "./storage";
import { trySyncRules } from "./sync";
/**
* 根据href匹配规则
@@ -134,3 +136,19 @@ export const checkRules = (rules) => {
return rules;
};
/**
* 保存或更新rule
* @param {*} newRule
*/
export const saveRule = async (newRule) => {
const rules = await getRulesWithDefault();
const rule = rules.find((item) => isMatch(newRule.pattern, item.pattern));
if (rule && rule.pattern !== GLOBAL_KEY) {
Object.assign(rule, { ...newRule, pattern: rule.pattern });
} else {
rules.unshift(newRule);
}
await setRules(rules);
trySyncRules();
};

View File

@@ -39,6 +39,10 @@ export const shortcutListener = (fn, target = document, timeout = 3000) => {
target.addEventListener("keydown", handleKeydown);
target.addEventListener("keyup", handleKeyup);
return () => {
if (timer) {
clearTimeout(timer);
timer = null;
}
target.removeEventListener("keydown", handleKeydown);
target.removeEventListener("keyup", handleKeyup);
};
@@ -51,9 +55,12 @@ export const shortcutListener = (fn, target = document, timeout = 3000) => {
* @param {*} target
* @returns
*/
export const shortcutRegister = (targetKeys, fn, target = document) => {
export const shortcutRegister = (targetKeys = [], fn, target = document) => {
return shortcutListener((curkeys) => {
if (isSameSet(new Set(targetKeys), new Set(curkeys))) {
if (
targetKeys.length > 0 &&
isSameSet(new Set(targetKeys), new Set(curkeys))
) {
fn();
}
}, target);

View File

@@ -20,7 +20,7 @@ import { sha256 } from "./utils";
* @returns
*/
const syncSetting = async (isBg = false) => {
const { syncUrl, syncKey, settingUpdateAt } = await getSyncWithDefault();
const { syncUrl, syncKey, settingUpdateAt = 0 } = await getSyncWithDefault();
if (!syncUrl || !syncKey) {
return;
}
@@ -37,16 +37,15 @@ const syncSetting = async (isBg = false) => {
isBg
);
if (res && res.updateAt > settingUpdateAt) {
await updateSync({
settingUpdateAt: res.updateAt,
settingSyncAt: res.updateAt,
});
if (res.updateAt > settingUpdateAt) {
await setSetting(res.value);
return res.value;
} else {
await updateSync({ settingSyncAt: res.updateAt });
}
await updateSync({
settingUpdateAt: res.updateAt,
settingSyncAt: Date.now(),
});
return res.value;
};
export const trySyncSetting = async (isBg = false) => {
@@ -79,16 +78,15 @@ const syncRules = async (isBg = false) => {
isBg
);
if (res && res.updateAt > rulesUpdateAt) {
await updateSync({
rulesUpdateAt: res.updateAt,
rulesSyncAt: res.updateAt,
});
if (res.updateAt > rulesUpdateAt) {
await setRules(res.value);
return res.value;
} else {
await updateSync({ rulesSyncAt: res.updateAt });
}
await updateSync({
rulesUpdateAt: res.updateAt,
rulesSyncAt: Date.now(),
});
return res.value;
};
export const trySyncRules = async (isBg = false) => {

View File

@@ -5,7 +5,8 @@ import { apiFetch } from "../apis";
/**
* 修复程序类型
*/
const WEBFIX_BR = "br";
const FIXER_BR = "br";
const FIXER_FONTSIZE = "fontSize";
/**
* 需要修复的站点列表
@@ -19,13 +20,19 @@ const DEFAULT_SITES = [
pattern: "www.phoronix.com",
selector: ".content",
rootSlector: "",
fixer: WEBFIX_BR,
fixer: FIXER_BR,
},
{
pattern: "t.me/s/*",
pattern: "t.me/s/",
selector: ".tgme_widget_message_text",
rootSlector: ".tgme_channel_history",
fixer: WEBFIX_BR,
fixer: FIXER_BR,
},
{
pattern: "baidu.com",
selector: "html",
rootSlector: "",
fixer: FIXER_FONTSIZE,
},
];
@@ -87,11 +94,20 @@ function brFixer(node) {
node.innerHTML = html;
}
/**
* 修复字体大小问题,如 baidu.com
* @param {*} node
*/
function fontSizeFixer(node) {
node.style.cssText += "font-size:1em;";
}
/**
* 修复程序映射
*/
const fixerMap = {
[WEBFIX_BR]: brFixer,
[FIXER_BR]: brFixer,
[FIXER_FONTSIZE]: fontSizeFixer,
};
/**

View File

@@ -14,6 +14,7 @@ import {
OPT_SHORTCUT_TRANSLATE,
OPT_SHORTCUT_STYLE,
OPT_SHORTCUT_POPUP,
OPT_SHORTCUT_SETTING,
} from "../../config";
import { shortcutRegister } from "../../libs/shortcut";
@@ -64,6 +65,9 @@ export default function Action({ translator, fab }) {
shortcutRegister(shortcuts[OPT_SHORTCUT_POPUP], () => {
setShowPopup((pre) => !pre);
}),
shortcutRegister(shortcuts[OPT_SHORTCUT_SETTING], () => {
window.open(process.env.REACT_APP_OPTIONSPAGE, "_blank");
}),
];
return () => {
@@ -80,7 +84,7 @@ export default function Action({ translator, fab }) {
try {
menuCommandIds.push(
GM.registerMenuCommand(
"Toggle Translate",
"Toggle Translate (Alt+q)",
(event) => {
translator.toggle();
setShowPopup(false);
@@ -88,7 +92,7 @@ export default function Action({ translator, fab }) {
"Q"
),
GM.registerMenuCommand(
"Toggle Style",
"Toggle Style (Alt+c)",
(event) => {
translator.toggleStyle();
setShowPopup(false);
@@ -96,11 +100,18 @@ export default function Action({ translator, fab }) {
"C"
),
GM.registerMenuCommand(
"Open Menu",
"Open Menu (Alt+k)",
(event) => {
setShowPopup((pre) => !pre);
},
"K"
),
GM.registerMenuCommand(
"Open Setting (Alt+o)",
(event) => {
window.open(process.env.REACT_APP_OPTIONSPAGE, "_blank");
},
"O"
)
);
} catch (err) {
@@ -183,7 +194,7 @@ export default function Action({ translator, fab }) {
key="fab"
snapEdge
{...fabProps}
show={!showPopup}
show={translator.setting.hideFab ? false : !showPopup}
onStart={handleStart}
onMove={handleMove}
handler={

View File

@@ -362,6 +362,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
}
function RuleAccordion({ rule, rules }) {
const i18n = useI18n();
const [expanded, setExpanded] = useState(false);
const handleChange = (e) => {
@@ -376,7 +377,9 @@ function RuleAccordion({ rule, rules }) {
opacity: rules ? 1 : 0.5,
}}
>
{rule.pattern}
{rule.pattern === GLOBAL_KEY
? `[${i18n("global_rule")}] ${rule.pattern}`
: rule.pattern}
</Typography>
</AccordionSummary>
<AccordionDetails>
@@ -655,7 +658,7 @@ function SubRulesItem({
<FormControlLabel value={url} control={<Radio />} label={url} />
{syncAt && (
<span style={{ marginLeft: "0.5em", opacity: 0.6 }}>
<span style={{ marginLeft: "0.5em", opacity: 0.5 }}>
[{new Date(syncAt).toLocaleString()}]
</span>
)}

View File

@@ -24,6 +24,7 @@ import {
OPT_SHORTCUT_TRANSLATE,
OPT_SHORTCUT_STYLE,
OPT_SHORTCUT_POPUP,
OPT_SHORTCUT_SETTING,
} from "../../config";
import { useEffect, useState, useRef } from "react";
import { useShortcut } from "../../hooks/Shortcut";
@@ -33,29 +34,26 @@ function ShortcutItem({ action, label }) {
const { shortcut, setShortcut } = useShortcut(action);
const [disabled, setDisabled] = useState(true);
const inputRef = useRef(null);
const [formval, setFormval] = useState(shortcut);
useEffect(() => {
if (disabled) {
setFormval(shortcut);
return;
}
inputRef.current.focus();
setFormval([]);
setShortcut([]);
const clearShortcut = shortcutListener((curkeys, allkeys) => {
setFormval(allkeys);
setShortcut(allkeys);
if (curkeys.length === 0) {
setDisabled(true);
setShortcut(allkeys);
}
}, inputRef.current);
return () => {
clearShortcut();
};
}, [disabled, setShortcut, shortcut]);
}, [disabled, setShortcut]);
return (
<Stack direction="row">
@@ -63,7 +61,7 @@ function ShortcutItem({ action, label }) {
size="small"
label={label}
name={label}
value={formval.join(" + ")}
value={shortcut.join(" + ")}
fullWidth
inputRef={inputRef}
disabled={disabled}
@@ -131,6 +129,7 @@ export default function Settings() {
clearCache,
newlineLength = TRANS_NEWLINE_LENGTH,
mouseKey = OPT_MOUSEKEY_DISABLE,
hideFab = false,
} = setting;
return (
@@ -232,26 +231,46 @@ export default function Settings() {
</FormHelperText>
</FormControl>
) : (
<Grid container rowSpacing={2} columns={12}>
<Grid item xs={12} sm={12} md={4} lg={4}>
<ShortcutItem
action={OPT_SHORTCUT_TRANSLATE}
label={i18n("toggle_translate_shortcut")}
/>
<>
<FormControl size="small">
<InputLabel>{i18n("hide_fab_button")}</InputLabel>
<Select
name="hideFab"
value={hideFab}
label={i18n("hide_fab_button")}
onChange={handleChange}
>
<MenuItem value={false}>{i18n("show")}</MenuItem>
<MenuItem value={true}>{i18n("hide")}</MenuItem>
</Select>
</FormControl>
<Grid container rowSpacing={2} columns={12}>
<Grid item xs={12} sm={12} md={3} lg={3}>
<ShortcutItem
action={OPT_SHORTCUT_TRANSLATE}
label={i18n("toggle_translate_shortcut")}
/>
</Grid>
<Grid item xs={12} sm={12} md={3} lg={3}>
<ShortcutItem
action={OPT_SHORTCUT_STYLE}
label={i18n("toggle_style_shortcut")}
/>
</Grid>
<Grid item xs={12} sm={12} md={3} lg={3}>
<ShortcutItem
action={OPT_SHORTCUT_POPUP}
label={i18n("toggle_popup_shortcut")}
/>
</Grid>
<Grid item xs={12} sm={12} md={3} lg={3}>
<ShortcutItem
action={OPT_SHORTCUT_SETTING}
label={i18n("open_setting_shortcut")}
/>
</Grid>
</Grid>
<Grid item xs={12} sm={12} md={4} lg={4}>
<ShortcutItem
action={OPT_SHORTCUT_STYLE}
label={i18n("toggle_style_shortcut")}
/>
</Grid>
<Grid item xs={12} sm={12} md={4} lg={4}>
<ShortcutItem
action={OPT_SHORTCUT_POPUP}
label={i18n("toggle_popup_shortcut")}
/>
</Grid>
</Grid>
</>
)}
</Stack>
</Box>

View File

@@ -1,6 +1,6 @@
import Stack from "@mui/material/Stack";
import TextField from "@mui/material/TextField";
import { useEffect, useState } from "react";
import { useCallback, useEffect, useState } from "react";
import { useI18n } from "../../hooks/I18n";
import Typography from "@mui/material/Typography";
import Accordion from "@mui/material/Accordion";
@@ -75,11 +75,17 @@ export default function Webfix() {
const alert = useAlert();
const { setting, updateSetting } = useSetting();
const loadSites = useCallback(async () => {
const sites = await loadOrFetchWebfix(process.env.REACT_APP_WEBFIXURL);
setSites(sites);
}, []);
const handleSyncTest = async (e) => {
e.preventDefault();
try {
setLoading(true);
await syncWebfix(process.env.REACT_APP_WEBFIXURL);
await loadSites();
alert.success(i18n("sync_success"));
} catch (err) {
console.log("[sync webfix]", err);
@@ -93,15 +99,14 @@ export default function Webfix() {
(async () => {
try {
setLoading(true);
const sites = await loadOrFetchWebfix(process.env.REACT_APP_WEBFIXURL);
setSites(sites);
await loadSites();
} catch (err) {
console.log("[load webfix]", err.message);
} finally {
setLoading(false);
}
})();
}, []);
}, [loadSites]);
return (
<Box>

View File

@@ -36,7 +36,7 @@ export default function Options() {
// 检查版本是否一致
if (version !== process.env.REACT_APP_VERSION) {
setError(
`The version of the script(v${version}) and this page(v${process.env.REACT_APP_VERSION}) are inconsistent.`
`The version is inconsistent, please check whether the script(v${version}) is the latest version(v${process.env.REACT_APP_VERSION}). (版本不一致,请检查脚本(v${version})是否为最新版(v${process.env.REACT_APP_VERSION}))`
);
break;
}
@@ -53,7 +53,7 @@ export default function Options() {
}
if (++i > 8) {
setError("Time out.");
setError("Time out. (连接超时)");
break;
}
@@ -78,26 +78,26 @@ export default function Options() {
</Divider>
<h2>
Please confirm whether to install or enable KISS Translator
GreaseMonkey script?
GreaseMonkey script? (请检查是否安装或启用简约翻译油猴脚本)
</h2>
<Stack spacing={2}>
<Link href={process.env.REACT_APP_USERSCRIPT_DOWNLOADURL}>
Install Userscript 1
Install Userscript for Tampermonkey/Violentmonkey 1 (油猴脚本 安装地址 1)
</Link>
<Link href={process.env.REACT_APP_USERSCRIPT_DOWNLOADURL2}>
Install Userscript 2
Install Userscript for Tampermonkey/Violentmonkey 2 (油猴脚本 安装地址 2)
</Link>
<Link href={process.env.REACT_APP_USERSCRIPT_IOS_DOWNLOADURL}>
Install Userscript Safari 1
Install Userscript for iOS Safari 1 (油猴脚本 iOS Safari专用 安装地址 1)
</Link>
<Link href={process.env.REACT_APP_USERSCRIPT_IOS_DOWNLOADURL2}>
Install Userscript Safari 2
Install Userscript for iOS Safari 2 (油猴脚本 iOS Safari专用 安装地址 2)
</Link>
<Link href={process.env.REACT_APP_OPTIONSPAGE}>
Open Options Page 1
Open Options Page 1 (打开设置页面 1)
</Link>
<Link href={process.env.REACT_APP_OPTIONSPAGE2}>
Open Options Page 2
Open Options Page 2 (打开设置页面 2)
</Link>
</Stack>
</center>

View File

@@ -5,7 +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 { sendTabMsg } from "../../libs/msg";
import { sendTabMsg, getTabInfo } from "../../libs/msg";
import { browser } from "../../libs/browser";
import { isExt } from "../../libs/client";
import { useI18n } from "../../hooks/I18n";
@@ -24,6 +24,7 @@ import {
CACHE_NAME,
} from "../../config";
import { sendIframeMsg } from "../../libs/iframe";
import { saveRule } from "../../libs/rules";
export default function Popup({ setShowPopup, translator: tran }) {
const i18n = useI18n();
@@ -77,6 +78,20 @@ export default function Popup({ setShowPopup, translator: tran }) {
}
};
const handleSaveRule = async () => {
try {
let host = window.location.host;
if (isExt) {
const tab = await getTabInfo();
const url = new URL(tab.url);
host = url.host;
}
saveRule({ ...rule, pattern: host });
} catch (err) {
console.log("[save rule]", err);
}
};
useEffect(() => {
if (!isExt) {
return;
@@ -218,9 +233,19 @@ export default function Popup({ setShowPopup, translator: tran }) {
/>
)}
<Button variant="text" onClick={handleOpenSetting}>
{i18n("setting")}
</Button>
<Stack
direction="row"
justifyContent="space-between"
alignItems="center"
spacing={2}
>
<Button variant="text" onClick={handleSaveRule}>
{i18n("save_rule")}
</Button>
<Button variant="text" onClick={handleOpenSetting}>
{i18n("setting")}
</Button>
</Stack>
</Stack>
</Box>
);