feat: tranbox hover trigger

This commit is contained in:
Gabe Yuan
2024-04-16 12:47:55 +08:00
parent 148a4e97a6
commit ca84bdb227
6 changed files with 110 additions and 40 deletions

View File

@@ -827,4 +827,20 @@ export const I18N = {
zh: `获取小牛翻译密钥`, zh: `获取小牛翻译密钥`,
en: `Get NiuTrans APIKey`, en: `Get NiuTrans APIKey`,
}, },
trigger_mode: {
zh: `触发方式`,
en: `Trigger Mode`,
},
trigger_click: {
zh: `点击触发`,
en: `Click Trigger`,
},
trigger_hover: {
zh: `鼠标悬停触发`,
en: `Hover Trigger`,
},
trigger_select: {
zh: `选中触发`,
en: `Select Trigger`,
},
}; };

View File

@@ -407,6 +407,14 @@ export const DEFAULT_INPUT_RULE = {
}; };
// 划词翻译 // 划词翻译
export const OPT_TRANBOX_TRIGGER_CLICK = "click";
export const OPT_TRANBOX_TRIGGER_HOVER = "hover";
export const OPT_TRANBOX_TRIGGER_SELECT = "select";
export const OPT_TRANBOX_TRIGGER_ALL = [
OPT_TRANBOX_TRIGGER_CLICK,
OPT_TRANBOX_TRIGGER_HOVER,
OPT_TRANBOX_TRIGGER_SELECT,
];
export const DEFAULT_TRANBOX_SHORTCUT = ["AltLeft", "KeyS"]; export const DEFAULT_TRANBOX_SHORTCUT = ["AltLeft", "KeyS"];
export const DEFAULT_TRANBOX_SETTING = { export const DEFAULT_TRANBOX_SETTING = {
transOpen: true, transOpen: true,
@@ -418,8 +426,9 @@ export const DEFAULT_TRANBOX_SETTING = {
btnOffsetX: 10, btnOffsetX: 10,
btnOffsetY: 10, btnOffsetY: 10,
hideTranBtn: false, // 是否隐藏翻译按钮 hideTranBtn: false, // 是否隐藏翻译按钮
hideClickAway: false, // 默认是否点击外部关闭弹窗 hideClickAway: false, // 是否点击外部关闭弹窗
simpleStyle: false, // 默认是否简洁界面 simpleStyle: false, // 是否简洁界面
triggerMode: OPT_TRANBOX_TRIGGER_CLICK, // 触发翻译方式
}; };
// 订阅列表 // 订阅列表

View File

@@ -366,7 +366,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
fullWidth fullWidth
name="transTiming" name="transTiming"
value={transTiming} value={transTiming}
label={i18n("translate_timing")} label={i18n("trigger_mode")}
disabled={disabled} disabled={disabled}
onChange={handleChange} onChange={handleChange}
> >

View File

@@ -3,7 +3,13 @@ import Stack from "@mui/material/Stack";
import TextField from "@mui/material/TextField"; import TextField from "@mui/material/TextField";
import MenuItem from "@mui/material/MenuItem"; import MenuItem from "@mui/material/MenuItem";
import { useI18n } from "../../hooks/I18n"; import { useI18n } from "../../hooks/I18n";
import { OPT_TRANS_ALL, OPT_LANGS_FROM, OPT_LANGS_TO } from "../../config"; import {
OPT_TRANS_ALL,
OPT_LANGS_FROM,
OPT_LANGS_TO,
OPT_TRANBOX_TRIGGER_CLICK,
OPT_TRANBOX_TRIGGER_ALL,
} from "../../config";
import ShortcutInput from "./ShortcutInput"; import ShortcutInput from "./ShortcutInput";
import FormControlLabel from "@mui/material/FormControlLabel"; import FormControlLabel from "@mui/material/FormControlLabel";
import Switch from "@mui/material/Switch"; import Switch from "@mui/material/Switch";
@@ -52,6 +58,7 @@ export default function Tranbox() {
hideTranBtn = false, hideTranBtn = false,
hideClickAway = false, hideClickAway = false,
simpleStyle = false, simpleStyle = false,
triggerMode = OPT_TRANBOX_TRIGGER_CLICK,
} = tranboxSetting; } = tranboxSetting;
return ( return (
@@ -186,6 +193,21 @@ export default function Tranbox() {
<MenuItem value={true}>{i18n("enable")}</MenuItem> <MenuItem value={true}>{i18n("enable")}</MenuItem>
</TextField> </TextField>
<TextField
select
size="small"
name="triggerMode"
value={triggerMode}
label={i18n("trigger_mode")}
onChange={handleChange}
>
{OPT_TRANBOX_TRIGGER_ALL.map((item) => (
<MenuItem key={item} value={item}>
{i18n(`trigger_${item}`)}
</MenuItem>
))}
</TextField>
{!isExt && ( {!isExt && (
<ShortcutInput <ShortcutInput
value={tranboxShortcut} value={tranboxShortcut}

View File

@@ -1,7 +1,12 @@
import { isMobile } from "../../libs/mobile"; import { isMobile } from "../../libs/mobile";
import { limitNumber } from "../../libs/utils"; import { limitNumber } from "../../libs/utils";
export default function TranBtn({ onClick, position, tranboxSetting }) { export default function TranBtn({
onTrigger,
btnEvent,
position,
tranboxSetting,
}) {
const left = limitNumber( const left = limitNumber(
position.x + tranboxSetting.btnOffsetX, position.x + tranboxSetting.btnOffsetX,
0, 0,
@@ -13,14 +18,6 @@ export default function TranBtn({ onClick, position, tranboxSetting }) {
window.innerHeight - 32 window.innerHeight - 32
); );
const touchProps = isMobile
? {
onTouchEnd: onClick,
}
: {
onMouseUp: onClick,
};
return ( return (
<div <div
style={{ style={{
@@ -31,7 +28,7 @@ export default function TranBtn({ onClick, position, tranboxSetting }) {
top, top,
zIndex: 2147483647, zIndex: 2147483647,
}} }}
{...touchProps} {...{ [btnEvent]: onTrigger }}
> >
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"

View File

@@ -1,10 +1,16 @@
import { useState, useEffect, useCallback } from "react"; import { useState, useEffect, useCallback, useMemo } from "react";
import TranBtn from "./TranBtn"; import TranBtn from "./TranBtn";
import TranBox from "./TranBox"; import TranBox from "./TranBox";
import { shortcutRegister } from "../../libs/shortcut"; import { shortcutRegister } from "../../libs/shortcut";
import { sleep, limitNumber } from "../../libs/utils"; import { sleep, limitNumber } from "../../libs/utils";
import { isGm, isExt } from "../../libs/client"; import { isGm, isExt } from "../../libs/client";
import { MSG_OPEN_TRANBOX, DEFAULT_TRANBOX_SHORTCUT } from "../../config"; import {
MSG_OPEN_TRANBOX,
DEFAULT_TRANBOX_SHORTCUT,
OPT_TRANBOX_TRIGGER_CLICK,
OPT_TRANBOX_TRIGGER_HOVER,
OPT_TRANBOX_TRIGGER_SELECT,
} from "../../config";
import { isMobile } from "../../libs/mobile"; import { isMobile } from "../../libs/mobile";
import { kissLog } from "../../libs/log"; import { kissLog } from "../../libs/log";
@@ -13,12 +19,20 @@ export default function Slection({
tranboxSetting, tranboxSetting,
transApis, transApis,
}) { }) {
const {
hideTranBtn = false,
simpleStyle: initSimpleStyle = false,
hideClickAway: initHideClickAway = false,
tranboxShortcut = DEFAULT_TRANBOX_SHORTCUT,
triggerMode = OPT_TRANBOX_TRIGGER_CLICK,
} = tranboxSetting;
const boxWidth = const boxWidth =
isMobile || tranboxSetting.simpleStyle isMobile || initSimpleStyle
? 300 ? 300
: limitNumber(window.innerWidth, 300, 600); : limitNumber(window.innerWidth, 300, 600);
const boxHeight = const boxHeight =
isMobile || tranboxSetting.simpleStyle isMobile || initSimpleStyle
? 200 ? 200
: limitNumber(window.innerHeight, 200, 400); : limitNumber(window.innerHeight, 200, 400);
@@ -35,18 +49,17 @@ export default function Slection({
x: (window.innerWidth - boxWidth) / 2, x: (window.innerWidth - boxWidth) / 2,
y: (window.innerHeight - boxHeight) / 2, y: (window.innerHeight - boxHeight) / 2,
}); });
const [simpleStyle, setSimpleStyle] = useState(!!tranboxSetting.simpleStyle); const [simpleStyle, setSimpleStyle] = useState(initSimpleStyle);
const [hideClickAway, setHideClickAway] = useState( const [hideClickAway, setHideClickAway] = useState(initHideClickAway);
!!tranboxSetting.hideClickAway
);
const handleClick = (e) => {
e.stopPropagation();
const handleTrigger = useCallback(
(text) => {
setShowBtn(false); setShowBtn(false);
setText(selectedText); setText(text || selectedText);
setShowBox(true); setShowBox(true);
}; },
[selectedText]
);
const handleTranbox = useCallback(() => { const handleTranbox = useCallback(() => {
setShowBtn(false); setShowBtn(false);
@@ -62,10 +75,19 @@ export default function Slection({
setShowBox(true); setShowBox(true);
}, []); }, []);
const btnEvent = useMemo(() => {
if (isMobile) {
return "onTouchEnd";
} else if (triggerMode === OPT_TRANBOX_TRIGGER_HOVER) {
return "onMouseOver";
}
return "onMouseUp";
}, [triggerMode]);
useEffect(() => { useEffect(() => {
async function handleMouseup(e) { async function handleMouseup(e) {
e.stopPropagation(); e.stopPropagation();
await sleep(100); await sleep(200);
const selectedText = window.getSelection()?.toString()?.trim() || ""; const selectedText = window.getSelection()?.toString()?.trim() || "";
setSelText(selectedText); setSelText(selectedText);
@@ -74,8 +96,13 @@ export default function Slection({
return; return;
} }
if (triggerMode === OPT_TRANBOX_TRIGGER_SELECT) {
handleTrigger(selectedText);
return;
}
const { clientX, clientY } = isMobile ? e.changedTouches[0] : e; const { clientX, clientY } = isMobile ? e.changedTouches[0] : e;
!tranboxSetting.hideTranBtn && setShowBtn(true); setShowBtn(!hideTranBtn);
// setPosition({ x: e.clientX, y: e.clientY }); // setPosition({ x: e.clientX, y: e.clientY });
setPosition({ x: clientX, y: clientY }); setPosition({ x: clientX, y: clientY });
} }
@@ -89,22 +116,17 @@ export default function Slection({
handleMouseup handleMouseup
); );
}; };
}, [tranboxSetting.hideTranBtn]); }, [hideTranBtn, triggerMode, handleTrigger]);
useEffect(() => { useEffect(() => {
if (isExt) { if (isExt) {
return; return;
} }
const clearShortcut = shortcutRegister(tranboxShortcut, handleTranbox);
const clearShortcut = shortcutRegister(
tranboxSetting.tranboxShortcut || DEFAULT_TRANBOX_SHORTCUT,
handleTranbox
);
return () => { return () => {
clearShortcut(); clearShortcut();
}; };
}, [tranboxSetting.tranboxShortcut, handleTranbox]); }, [tranboxShortcut, handleTranbox]);
useEffect(() => { useEffect(() => {
window.addEventListener(MSG_OPEN_TRANBOX, handleTranbox); window.addEventListener(MSG_OPEN_TRANBOX, handleTranbox);
@@ -178,7 +200,11 @@ export default function Slection({
<TranBtn <TranBtn
position={position} position={position}
tranboxSetting={tranboxSetting} tranboxSetting={tranboxSetting}
onClick={handleClick} btnEvent={btnEvent}
onTrigger={(e) => {
e.stopPropagation();
handleTrigger();
}}
/> />
)} )}
</> </>