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 && ( <>