add fab for ext

This commit is contained in:
Gabe Yuan
2023-09-23 19:16:51 +08:00
parent a395f0b31b
commit e17931493b
9 changed files with 102 additions and 33 deletions

View File

@@ -4,6 +4,8 @@ import {
MSG_FETCH_LIMIT, MSG_FETCH_LIMIT,
MSG_FETCH_CLEAR, MSG_FETCH_CLEAR,
MSG_TRANS_TOGGLE, MSG_TRANS_TOGGLE,
MSG_OPEN_OPTIONS,
MSG_SAVE_RULE,
MSG_TRANS_TOGGLE_STYLE, MSG_TRANS_TOGGLE_STYLE,
CMD_TOGGLE_TRANSLATE, CMD_TOGGLE_TRANSLATE,
CMD_TOGGLE_STYLE, CMD_TOGGLE_STYLE,
@@ -15,6 +17,7 @@ import { fetchData, fetchPool } from "./libs/fetch";
import { sendTabMsg } from "./libs/msg"; import { sendTabMsg } from "./libs/msg";
import { trySyncAllSubRules } from "./libs/subRules"; import { trySyncAllSubRules } from "./libs/subRules";
import { tryClearCaches } from "./libs"; import { tryClearCaches } from "./libs";
import { saveRule } from "./libs/rules";
globalThis.ContextType = "BACKGROUND"; globalThis.ContextType = "BACKGROUND";
@@ -69,6 +72,12 @@ browser.runtime.onMessage.addListener(
fetchPool.clear(); fetchPool.clear();
sendResponse({ data: "ok" }); sendResponse({ data: "ok" });
break; break;
case MSG_OPEN_OPTIONS:
browser.runtime.openOptionsPage();
break;
case MSG_SAVE_RULE:
saveRule(args);
break;
default: default:
sendResponse({ error: `message action is unavailable: ${action}` }); sendResponse({ error: `message action is unavailable: ${action}` });
} }

View File

@@ -49,6 +49,8 @@ export const CACHE_NAME = `${APP_NAME}_cache`;
export const MSG_FETCH = "fetch"; export const MSG_FETCH = "fetch";
export const MSG_FETCH_LIMIT = "fetch_limit"; export const MSG_FETCH_LIMIT = "fetch_limit";
export const MSG_FETCH_CLEAR = "fetch_clear"; 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 = "trans_toggle";
export const MSG_TRANS_TOGGLE_STYLE = "trans_toggle_style"; export const MSG_TRANS_TOGGLE_STYLE = "trans_toggle_style";
export const MSG_TRANS_GETRULE = "trans_getrule"; export const MSG_TRANS_GETRULE = "trans_getrule";
@@ -287,7 +289,6 @@ export const DEFAULT_SETTING = {
transApis: DEFAULT_TRANS_APIS, // 翻译接口 transApis: DEFAULT_TRANS_APIS, // 翻译接口
mouseKey: OPT_MOUSEKEY_DISABLE, // 鼠标悬停翻译 mouseKey: OPT_MOUSEKEY_DISABLE, // 鼠标悬停翻译
shortcuts: DEFAULT_SHORTCUTS, // 快捷键 shortcuts: DEFAULT_SHORTCUTS, // 快捷键
hideFab: false, // 是否隐藏按钮
inputRule: DEFAULT_INPUT_RULE, // 输入框设置 inputRule: DEFAULT_INPUT_RULE, // 输入框设置
}; };
@@ -303,10 +304,6 @@ export const DEFAULT_SYNC = {
syncUser: "", // 数据同步用户名 syncUser: "", // 数据同步用户名
syncKey: "", // 数据同步密钥 syncKey: "", // 数据同步密钥
syncMeta: {}, // 数据更新及同步信息 syncMeta: {}, // 数据更新及同步信息
// settingUpdateAt: 0,
// settingSyncAt: 0,
// rulesUpdateAt: 0,
// rulesSyncAt: 0,
subRulesSyncAt: 0, // 订阅规则同步时间 subRulesSyncAt: 0, // 订阅规则同步时间
dataCaches: {}, // 缓存同步时间 dataCaches: {}, // 缓存同步时间
}; };

View File

@@ -1,11 +1,20 @@
import { browser } from "./libs/browser"; 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 { import {
MSG_TRANS_TOGGLE, MSG_TRANS_TOGGLE,
MSG_TRANS_TOGGLE_STYLE, MSG_TRANS_TOGGLE_STYLE,
MSG_TRANS_GETRULE, MSG_TRANS_GETRULE,
MSG_TRANS_PUTRULE, MSG_TRANS_PUTRULE,
} from "./config"; } from "./config";
import { getSettingWithDefault, getRulesWithDefault } from "./libs/storage"; import {
getSettingWithDefault,
getRulesWithDefault,
getFabWithDefault,
} from "./libs/storage";
import { Translator } from "./libs/translator"; import { Translator } from "./libs/translator";
import { isIframe, sendIframeMsg, sendPrentMsg } from "./libs/iframe"; import { isIframe, sendIframeMsg, sendPrentMsg } from "./libs/iframe";
import { matchRule } from "./libs/rules"; import { matchRule } from "./libs/rules";
@@ -79,6 +88,31 @@ const init = async () => {
default: 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(
<React.StrictMode>
<CacheProvider value={cache}>
<Action translator={translator} fab={fab} />
</CacheProvider>
</React.StrictMode>
);
}
}; };
(async () => { (async () => {

11
src/hooks/Fab.js Normal file
View File

@@ -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 };
}

View File

@@ -119,6 +119,7 @@ export const setWebfix = (url, val) =>
export const getFab = () => getObj(STOKEY_FAB); export const getFab = () => getObj(STOKEY_FAB);
export const getFabWithDefault = async () => (await getFab()) || {}; export const getFabWithDefault = async () => (await getFab()) || {};
export const setFab = (obj) => setObj(STOKEY_FAB, obj); export const setFab = (obj) => setObj(STOKEY_FAB, obj);
export const updateFab = (obj) => putObj(STOKEY_FAB, obj);
/** /**
* 数据同步 * 数据同步

View File

@@ -1,7 +1,7 @@
import { useEffect, useMemo, useState } from "react"; import { useEffect, useMemo, useState } from "react";
import { limitNumber } from "../../libs/utils"; import { limitNumber } from "../../libs/utils";
import { isMobile } from "../../libs/mobile"; import { isMobile } from "../../libs/mobile";
import { setFab } from "../../libs/storage"; import { updateFab } from "../../libs/storage";
import { debounce } from "../../libs/utils"; import { debounce } from "../../libs/utils";
import Paper from "@mui/material/Paper"; import Paper from "@mui/material/Paper";
@@ -61,7 +61,7 @@ export default function Draggable({
const [hover, setHover] = useState(false); const [hover, setHover] = useState(false);
const [origin, setOrigin] = useState(null); const [origin, setOrigin] = useState(null);
const [position, setPosition] = useState({ x: left, y: top }); const [position, setPosition] = useState({ x: left, y: top });
const setFabPosition = useMemo(() => debounce(setFab, 500), []); const setFabPosition = useMemo(() => debounce(updateFab, 500), []);
const handlePointerDown = (e) => { const handlePointerDown = (e) => {
!isMobile && e.target.setPointerCapture(e.pointerId); !isMobile && e.target.setPointerCapture(e.pointerId);

View File

@@ -55,6 +55,10 @@ export default function Action({ translator, fab }) {
}, []); }, []);
useEffect(() => { useEffect(() => {
if (!isGm) {
return;
}
// 注册快捷键 // 注册快捷键
const shortcuts = translator.setting.shortcuts || DEFAULT_SHORTCUTS; const shortcuts = translator.setting.shortcuts || DEFAULT_SHORTCUTS;
const clearShortcuts = [ const clearShortcuts = [
@@ -198,7 +202,7 @@ export default function Action({ translator, fab }) {
key="fab" key="fab"
snapEdge snapEdge
{...fabProps} {...fabProps}
show={translator.setting.hideFab ? false : !showPopup} show={fab.isHide ? false : !showPopup}
onStart={handleStart} onStart={handleStart}
onMove={handleMove} onMove={handleMove}
handler={ handler={

View File

@@ -26,6 +26,7 @@ import {
} from "../../config"; } from "../../config";
import { useShortcut } from "../../hooks/Shortcut"; import { useShortcut } from "../../hooks/Shortcut";
import ShortcutInput from "./ShortcutInput"; import ShortcutInput from "./ShortcutInput";
import { useFab } from "../../hooks/Fab";
function ShortcutItem({ action, label }) { function ShortcutItem({ action, label }) {
const { shortcut, setShortcut } = useShortcut(action); const { shortcut, setShortcut } = useShortcut(action);
@@ -38,6 +39,7 @@ export default function Settings() {
const i18n = useI18n(); const i18n = useI18n();
const { setting, updateSetting } = useSetting(); const { setting, updateSetting } = useSetting();
const alert = useAlert(); const alert = useAlert();
const { fab, updateFab } = useFab();
const handleChange = (e) => { const handleChange = (e) => {
e.preventDefault(); e.preventDefault();
@@ -83,8 +85,8 @@ export default function Settings() {
clearCache, clearCache,
newlineLength = TRANS_NEWLINE_LENGTH, newlineLength = TRANS_NEWLINE_LENGTH,
mouseKey = OPT_MOUSEKEY_DISABLE, mouseKey = OPT_MOUSEKEY_DISABLE,
hideFab = false,
} = setting; } = setting;
const { isHide = false } = fab || {};
return ( return (
<Box> <Box>
@@ -166,6 +168,21 @@ export default function Settings() {
</Select> </Select>
</FormControl> </FormControl>
<FormControl size="small">
<InputLabel>{i18n("hide_fab_button")}</InputLabel>
<Select
name="isHide"
value={isHide}
label={i18n("hide_fab_button")}
onChange={(e) => {
updateFab({ isHide: e.target.value });
}}
>
<MenuItem value={false}>{i18n("show")}</MenuItem>
<MenuItem value={true}>{i18n("hide")}</MenuItem>
</Select>
</FormControl>
{isExt ? ( {isExt ? (
<FormControl size="small"> <FormControl size="small">
<InputLabel>{i18n("if_clear_cache")}</InputLabel> <InputLabel>{i18n("if_clear_cache")}</InputLabel>
@@ -186,19 +203,6 @@ export default function Settings() {
</FormControl> </FormControl>
) : ( ) : (
<> <>
<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>
<Box> <Box>
<Grid container spacing={2} columns={12}> <Grid container spacing={2} columns={12}>
<Grid item xs={12} sm={12} md={3} lg={3}> <Grid item xs={12} sm={12} md={3} lg={3}>

View File

@@ -5,7 +5,7 @@ import MenuItem from "@mui/material/MenuItem";
import FormControlLabel from "@mui/material/FormControlLabel"; import FormControlLabel from "@mui/material/FormControlLabel";
import Switch from "@mui/material/Switch"; import Switch from "@mui/material/Switch";
import Button from "@mui/material/Button"; 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 { browser } from "../../libs/browser";
import { isExt } from "../../libs/client"; import { isExt } from "../../libs/client";
import { useI18n } from "../../hooks/I18n"; import { useI18n } from "../../hooks/I18n";
@@ -16,6 +16,8 @@ import {
MSG_TRANS_TOGGLE, MSG_TRANS_TOGGLE,
MSG_TRANS_GETRULE, MSG_TRANS_GETRULE,
MSG_TRANS_PUTRULE, MSG_TRANS_PUTRULE,
MSG_OPEN_OPTIONS,
MSG_SAVE_RULE,
OPT_TRANS_ALL, OPT_TRANS_ALL,
OPT_LANGS_FROM, OPT_LANGS_FROM,
OPT_LANGS_TO, OPT_LANGS_TO,
@@ -31,8 +33,10 @@ export default function Popup({ setShowPopup, translator: tran }) {
const [rule, setRule] = useState(tran?.rule); const [rule, setRule] = useState(tran?.rule);
const handleOpenSetting = () => { const handleOpenSetting = () => {
if (isExt) { if (!tran) {
browser?.runtime.openOptionsPage(); browser?.runtime.openOptionsPage();
} else if (isExt) {
sendBgMsg(MSG_OPEN_OPTIONS);
} else { } else {
window.open(process.env.REACT_APP_OPTIONSPAGE, "_blank"); window.open(process.env.REACT_APP_OPTIONSPAGE, "_blank");
} }
@@ -43,7 +47,7 @@ export default function Popup({ setShowPopup, translator: tran }) {
try { try {
setRule({ ...rule, transOpen: e.target.checked ? "true" : "false" }); setRule({ ...rule, transOpen: e.target.checked ? "true" : "false" });
if (isExt) { if (!tran) {
await sendTabMsg(MSG_TRANS_TOGGLE); await sendTabMsg(MSG_TRANS_TOGGLE);
} else { } else {
tran.toggle(); tran.toggle();
@@ -59,7 +63,7 @@ export default function Popup({ setShowPopup, translator: tran }) {
const { name, value } = e.target; const { name, value } = e.target;
setRule((pre) => ({ ...pre, [name]: value })); setRule((pre) => ({ ...pre, [name]: value }));
if (isExt) { if (!tran) {
await sendTabMsg(MSG_TRANS_PUTRULE, { [name]: value }); await sendTabMsg(MSG_TRANS_PUTRULE, { [name]: value });
} else { } else {
tran.updateRule({ [name]: value }); tran.updateRule({ [name]: value });
@@ -77,18 +81,23 @@ export default function Popup({ setShowPopup, translator: tran }) {
const handleSaveRule = async () => { const handleSaveRule = async () => {
try { try {
let href = window.location.href; let href = window.location.href;
if (isExt) { if (!tran) {
const tab = await getTabInfo(); const tab = await getTabInfo();
href = tab.url; 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) { } catch (err) {
console.log("[save rule]", err); console.log("[save rule]", err);
} }
}; };
useEffect(() => { useEffect(() => {
if (!isExt) { if (tran) {
return; return;
} }
(async () => { (async () => {
@@ -101,12 +110,12 @@ export default function Popup({ setShowPopup, translator: tran }) {
console.log("[query rule]", err); console.log("[query rule]", err);
} }
})(); })();
}, []); }, [tran]);
if (!rule) { if (!rule) {
return ( return (
<Box minWidth={300}> <Box minWidth={300}>
{isExt && ( {!tran && (
<> <>
<Header /> <Header />
<Divider /> <Divider />
@@ -125,7 +134,7 @@ export default function Popup({ setShowPopup, translator: tran }) {
return ( return (
<Box minWidth={300}> <Box minWidth={300}>
{isExt && ( {!tran && (
<> <>
<Header /> <Header />
<Divider /> <Divider />