diff --git a/src/background.js b/src/background.js
index 9915457..3c6862f 100644
--- a/src/background.js
+++ b/src/background.js
@@ -4,6 +4,8 @@ import {
MSG_FETCH_LIMIT,
MSG_FETCH_CLEAR,
MSG_TRANS_TOGGLE,
+ MSG_OPEN_OPTIONS,
+ MSG_SAVE_RULE,
MSG_TRANS_TOGGLE_STYLE,
CMD_TOGGLE_TRANSLATE,
CMD_TOGGLE_STYLE,
@@ -15,6 +17,7 @@ import { fetchData, fetchPool } from "./libs/fetch";
import { sendTabMsg } from "./libs/msg";
import { trySyncAllSubRules } from "./libs/subRules";
import { tryClearCaches } from "./libs";
+import { saveRule } from "./libs/rules";
globalThis.ContextType = "BACKGROUND";
@@ -69,6 +72,12 @@ browser.runtime.onMessage.addListener(
fetchPool.clear();
sendResponse({ data: "ok" });
break;
+ case MSG_OPEN_OPTIONS:
+ browser.runtime.openOptionsPage();
+ break;
+ case MSG_SAVE_RULE:
+ saveRule(args);
+ break;
default:
sendResponse({ error: `message action is unavailable: ${action}` });
}
diff --git a/src/config/index.js b/src/config/index.js
index 4296998..f336cac 100644
--- a/src/config/index.js
+++ b/src/config/index.js
@@ -49,6 +49,8 @@ export const CACHE_NAME = `${APP_NAME}_cache`;
export const MSG_FETCH = "fetch";
export const MSG_FETCH_LIMIT = "fetch_limit";
export const MSG_FETCH_CLEAR = "fetch_clear";
+export const MSG_OPEN_OPTIONS = "open_options";
+export const MSG_SAVE_RULE = "save_rule";
export const MSG_TRANS_TOGGLE = "trans_toggle";
export const MSG_TRANS_TOGGLE_STYLE = "trans_toggle_style";
export const MSG_TRANS_GETRULE = "trans_getrule";
@@ -287,7 +289,6 @@ export const DEFAULT_SETTING = {
transApis: DEFAULT_TRANS_APIS, // 翻译接口
mouseKey: OPT_MOUSEKEY_DISABLE, // 鼠标悬停翻译
shortcuts: DEFAULT_SHORTCUTS, // 快捷键
- hideFab: false, // 是否隐藏按钮
inputRule: DEFAULT_INPUT_RULE, // 输入框设置
};
@@ -303,10 +304,6 @@ export const DEFAULT_SYNC = {
syncUser: "", // 数据同步用户名
syncKey: "", // 数据同步密钥
syncMeta: {}, // 数据更新及同步信息
- // settingUpdateAt: 0,
- // settingSyncAt: 0,
- // rulesUpdateAt: 0,
- // rulesSyncAt: 0,
subRulesSyncAt: 0, // 订阅规则同步时间
dataCaches: {}, // 缓存同步时间
};
diff --git a/src/content.js b/src/content.js
index 5b7a887..5f3f26b 100644
--- a/src/content.js
+++ b/src/content.js
@@ -1,11 +1,20 @@
import { browser } from "./libs/browser";
+import React from "react";
+import ReactDOM from "react-dom/client";
+import Action from "./views/Action";
+import createCache from "@emotion/cache";
+import { CacheProvider } from "@emotion/react";
import {
MSG_TRANS_TOGGLE,
MSG_TRANS_TOGGLE_STYLE,
MSG_TRANS_GETRULE,
MSG_TRANS_PUTRULE,
} from "./config";
-import { getSettingWithDefault, getRulesWithDefault } from "./libs/storage";
+import {
+ getSettingWithDefault,
+ getRulesWithDefault,
+ getFabWithDefault,
+} from "./libs/storage";
import { Translator } from "./libs/translator";
import { isIframe, sendIframeMsg, sendPrentMsg } from "./libs/iframe";
import { matchRule } from "./libs/rules";
@@ -79,6 +88,31 @@ const init = async () => {
default:
}
});
+
+ // 浮球按钮
+ const fab = await getFabWithDefault();
+ if (!fab.isHide) {
+ const $action = document.createElement("div");
+ $action.setAttribute("id", "kiss-translator");
+ document.body.parentElement.appendChild($action);
+ const shadowContainer = $action.attachShadow({ mode: "closed" });
+ const emotionRoot = document.createElement("style");
+ const shadowRootElement = document.createElement("div");
+ shadowContainer.appendChild(emotionRoot);
+ shadowContainer.appendChild(shadowRootElement);
+ const cache = createCache({
+ key: "css",
+ prepend: true,
+ container: emotionRoot,
+ });
+ ReactDOM.createRoot(shadowRootElement).render(
+
+
+
+
+
+ );
+ }
};
(async () => {
diff --git a/src/hooks/Fab.js b/src/hooks/Fab.js
new file mode 100644
index 0000000..36220a4
--- /dev/null
+++ b/src/hooks/Fab.js
@@ -0,0 +1,11 @@
+import { STOKEY_FAB } from "../config";
+import { useStorage } from "./Storage";
+
+/**
+ * fab hook
+ * @returns
+ */
+export function useFab() {
+ const { data, update } = useStorage(STOKEY_FAB);
+ return { fab: data, updateFab: update };
+}
diff --git a/src/libs/storage.js b/src/libs/storage.js
index 5a42c58..9c607e7 100644
--- a/src/libs/storage.js
+++ b/src/libs/storage.js
@@ -119,6 +119,7 @@ export const setWebfix = (url, val) =>
export const getFab = () => getObj(STOKEY_FAB);
export const getFabWithDefault = async () => (await getFab()) || {};
export const setFab = (obj) => setObj(STOKEY_FAB, obj);
+export const updateFab = (obj) => putObj(STOKEY_FAB, obj);
/**
* 数据同步
diff --git a/src/views/Action/Draggable.js b/src/views/Action/Draggable.js
index 34bab36..b503240 100644
--- a/src/views/Action/Draggable.js
+++ b/src/views/Action/Draggable.js
@@ -1,7 +1,7 @@
import { useEffect, useMemo, useState } from "react";
import { limitNumber } from "../../libs/utils";
import { isMobile } from "../../libs/mobile";
-import { setFab } from "../../libs/storage";
+import { updateFab } from "../../libs/storage";
import { debounce } from "../../libs/utils";
import Paper from "@mui/material/Paper";
@@ -61,7 +61,7 @@ export default function Draggable({
const [hover, setHover] = useState(false);
const [origin, setOrigin] = useState(null);
const [position, setPosition] = useState({ x: left, y: top });
- const setFabPosition = useMemo(() => debounce(setFab, 500), []);
+ const setFabPosition = useMemo(() => debounce(updateFab, 500), []);
const handlePointerDown = (e) => {
!isMobile && e.target.setPointerCapture(e.pointerId);
diff --git a/src/views/Action/index.js b/src/views/Action/index.js
index 511a07d..d998fb0 100644
--- a/src/views/Action/index.js
+++ b/src/views/Action/index.js
@@ -55,6 +55,10 @@ export default function Action({ translator, fab }) {
}, []);
useEffect(() => {
+ if (!isGm) {
+ return;
+ }
+
// 注册快捷键
const shortcuts = translator.setting.shortcuts || DEFAULT_SHORTCUTS;
const clearShortcuts = [
@@ -198,7 +202,7 @@ export default function Action({ translator, fab }) {
key="fab"
snapEdge
{...fabProps}
- show={translator.setting.hideFab ? false : !showPopup}
+ show={fab.isHide ? false : !showPopup}
onStart={handleStart}
onMove={handleMove}
handler={
diff --git a/src/views/Options/Setting.js b/src/views/Options/Setting.js
index 6733088..d977d30 100644
--- a/src/views/Options/Setting.js
+++ b/src/views/Options/Setting.js
@@ -26,6 +26,7 @@ import {
} from "../../config";
import { useShortcut } from "../../hooks/Shortcut";
import ShortcutInput from "./ShortcutInput";
+import { useFab } from "../../hooks/Fab";
function ShortcutItem({ action, label }) {
const { shortcut, setShortcut } = useShortcut(action);
@@ -38,6 +39,7 @@ export default function Settings() {
const i18n = useI18n();
const { setting, updateSetting } = useSetting();
const alert = useAlert();
+ const { fab, updateFab } = useFab();
const handleChange = (e) => {
e.preventDefault();
@@ -83,8 +85,8 @@ export default function Settings() {
clearCache,
newlineLength = TRANS_NEWLINE_LENGTH,
mouseKey = OPT_MOUSEKEY_DISABLE,
- hideFab = false,
} = setting;
+ const { isHide = false } = fab || {};
return (
@@ -166,6 +168,21 @@ export default function Settings() {
+
+ {i18n("hide_fab_button")}
+
+
+
{isExt ? (
{i18n("if_clear_cache")}
@@ -186,19 +203,6 @@ export default function Settings() {
) : (
<>
-
- {i18n("hide_fab_button")}
-
-
-
diff --git a/src/views/Popup/index.js b/src/views/Popup/index.js
index 0c0850d..7edfedd 100644
--- a/src/views/Popup/index.js
+++ b/src/views/Popup/index.js
@@ -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, getTabInfo } from "../../libs/msg";
+import { sendBgMsg, sendTabMsg, getTabInfo } from "../../libs/msg";
import { browser } from "../../libs/browser";
import { isExt } from "../../libs/client";
import { useI18n } from "../../hooks/I18n";
@@ -16,6 +16,8 @@ import {
MSG_TRANS_TOGGLE,
MSG_TRANS_GETRULE,
MSG_TRANS_PUTRULE,
+ MSG_OPEN_OPTIONS,
+ MSG_SAVE_RULE,
OPT_TRANS_ALL,
OPT_LANGS_FROM,
OPT_LANGS_TO,
@@ -31,8 +33,10 @@ export default function Popup({ setShowPopup, translator: tran }) {
const [rule, setRule] = useState(tran?.rule);
const handleOpenSetting = () => {
- if (isExt) {
+ if (!tran) {
browser?.runtime.openOptionsPage();
+ } else if (isExt) {
+ sendBgMsg(MSG_OPEN_OPTIONS);
} else {
window.open(process.env.REACT_APP_OPTIONSPAGE, "_blank");
}
@@ -43,7 +47,7 @@ export default function Popup({ setShowPopup, translator: tran }) {
try {
setRule({ ...rule, transOpen: e.target.checked ? "true" : "false" });
- if (isExt) {
+ if (!tran) {
await sendTabMsg(MSG_TRANS_TOGGLE);
} else {
tran.toggle();
@@ -59,7 +63,7 @@ export default function Popup({ setShowPopup, translator: tran }) {
const { name, value } = e.target;
setRule((pre) => ({ ...pre, [name]: value }));
- if (isExt) {
+ if (!tran) {
await sendTabMsg(MSG_TRANS_PUTRULE, { [name]: value });
} else {
tran.updateRule({ [name]: value });
@@ -77,18 +81,23 @@ export default function Popup({ setShowPopup, translator: tran }) {
const handleSaveRule = async () => {
try {
let href = window.location.href;
- if (isExt) {
+ if (!tran) {
const tab = await getTabInfo();
href = tab.url;
}
- saveRule({ ...rule, pattern: href });
+ const rule = { ...rule, pattern: href };
+ if (isExt && tran) {
+ sendBgMsg(MSG_SAVE_RULE, rule);
+ } else {
+ saveRule(rule);
+ }
} catch (err) {
console.log("[save rule]", err);
}
};
useEffect(() => {
- if (!isExt) {
+ if (tran) {
return;
}
(async () => {
@@ -101,12 +110,12 @@ export default function Popup({ setShowPopup, translator: tran }) {
console.log("[query rule]", err);
}
})();
- }, []);
+ }, [tran]);
if (!rule) {
return (
- {isExt && (
+ {!tran && (
<>
@@ -125,7 +134,7 @@ export default function Popup({ setShowPopup, translator: tran }) {
return (
- {isExt && (
+ {!tran && (
<>