Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b6148302d | ||
|
|
38c781b8f3 | ||
|
|
64d827fdcd | ||
|
|
74ad812f37 | ||
|
|
364c829119 | ||
|
|
1ac2c5b61e | ||
|
|
0766199353 | ||
|
|
878bccf151 | ||
|
|
acbd258296 | ||
|
|
54a14e6e5a |
2
.env
2
.env
@@ -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.10
|
||||
|
||||
REACT_APP_HOMEPAGE=https://github.com/fishjar/kiss-translator
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "kiss-translator",
|
||||
"description": "A minimalist bilingual translation Extension & Greasemonkey Script",
|
||||
"version": "1.6.8",
|
||||
"version": "1.6.10",
|
||||
"author": "Gabe<yugang2002@gmail.com>",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"manifest_version": 2,
|
||||
"name": "__MSG_app_name__",
|
||||
"description": "__MSG_app_description__",
|
||||
"version": "1.6.8",
|
||||
"version": "1.6.10",
|
||||
"default_locale": "en",
|
||||
"author": "Gabe<yugang2002@gmail.com>",
|
||||
"homepage_url": "https://github.com/fishjar/kiss-translator",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"manifest_version": 3,
|
||||
"name": "__MSG_app_name__",
|
||||
"description": "__MSG_app_description__",
|
||||
"version": "1.6.8",
|
||||
"version": "1.6.10",
|
||||
"default_locale": "en",
|
||||
"author": "Gabe<yugang2002@gmail.com>",
|
||||
"homepage_url": "https://github.com/fishjar/kiss-translator",
|
||||
|
||||
@@ -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,20 @@ 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`,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -243,10 +243,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 +271,7 @@ export const DEFAULT_SETTING = {
|
||||
transApis: DEFAULT_TRANS_APIS, // 翻译接口
|
||||
mouseKey: OPT_MOUSEKEY_DISABLE, // 鼠标悬停翻译
|
||||
shortcuts: DEFAULT_SHORTCUTS, // 快捷键
|
||||
hideFab: false, // 是否隐藏按钮
|
||||
};
|
||||
|
||||
export const DEFAULT_RULES = [GLOBLA_RULE];
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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={
|
||||
|
||||
@@ -655,7 +655,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>
|
||||
)}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user