feat: transbox follow selection

This commit is contained in:
Gabe Yuan
2024-04-20 18:07:16 +08:00
parent d622db0d7c
commit 74bc58ba91
6 changed files with 73 additions and 22 deletions

View File

@@ -861,4 +861,8 @@ export const I18N = {
zh: `打开设置`, zh: `打开设置`,
en: `Open Setting`, en: `Open Setting`,
}, },
follow_selection: {
zh: `翻译框跟随选中文本`,
en: `Transbox Follow Selection`,
},
}; };

View File

@@ -434,6 +434,7 @@ export const DEFAULT_TRANBOX_SETTING = {
hideTranBtn: false, // 是否隐藏翻译按钮 hideTranBtn: false, // 是否隐藏翻译按钮
hideClickAway: false, // 是否点击外部关闭弹窗 hideClickAway: false, // 是否点击外部关闭弹窗
simpleStyle: false, // 是否简洁界面 simpleStyle: false, // 是否简洁界面
followSelection: false, // 翻译框是否跟随选中文本
triggerMode: OPT_TRANBOX_TRIGGER_CLICK, // 触发翻译方式 triggerMode: OPT_TRANBOX_TRIGGER_CLICK, // 触发翻译方式
extStyles: "", // 附加样式 extStyles: "", // 附加样式
}; };

View File

@@ -58,6 +58,7 @@ export default function Tranbox() {
hideTranBtn = false, hideTranBtn = false,
hideClickAway = false, hideClickAway = false,
simpleStyle = false, simpleStyle = false,
followSelection = false,
triggerMode = OPT_TRANBOX_TRIGGER_CLICK, triggerMode = OPT_TRANBOX_TRIGGER_CLICK,
extStyles = "", extStyles = "",
} = tranboxSetting; } = tranboxSetting;
@@ -194,6 +195,18 @@ export default function Tranbox() {
<MenuItem value={true}>{i18n("enable")}</MenuItem> <MenuItem value={true}>{i18n("enable")}</MenuItem>
</TextField> </TextField>
<TextField
select
size="small"
name="followSelection"
value={followSelection}
label={i18n("follow_selection")}
onChange={handleChange}
>
<MenuItem value={false}>{i18n("disable")}</MenuItem>
<MenuItem value={true}>{i18n("enable")}</MenuItem>
</TextField>
<TextField <TextField
select select
size="small" size="small"

View File

@@ -1,4 +1,4 @@
import { useEffect, useState } from "react"; import { useState } from "react";
import Paper from "@mui/material/Paper"; import Paper from "@mui/material/Paper";
import Box from "@mui/material/Box"; import Box from "@mui/material/Box";
import { isMobile } from "../../libs/mobile"; import { isMobile } from "../../libs/mobile";
@@ -130,11 +130,11 @@ function Pointer({
export default function DraggableResizable({ export default function DraggableResizable({
header, header,
children, children,
defaultPosition = { position = {
x: 0, x: 0,
y: 0, y: 0,
}, },
defaultSize = { size = {
w: 600, w: 600,
h: 400, h: 400,
}, },
@@ -146,14 +146,13 @@ export default function DraggableResizable({
w: 1200, w: 1200,
h: 1200, h: 1200,
}, },
setSize,
setPosition,
onChangeSize, onChangeSize,
onChangePosition, onChangePosition,
...props ...props
}) { }) {
const lineWidth = 4; const lineWidth = 4;
const [position, setPosition] = useState(defaultPosition);
const [size, setSize] = useState(defaultSize);
const opts = { const opts = {
size, size,
setSize, setSize,
@@ -163,14 +162,6 @@ export default function DraggableResizable({
maxSize, maxSize,
}; };
useEffect(() => {
onChangeSize && onChangeSize(size);
}, [size, onChangeSize]);
useEffect(() => {
onChangePosition && onChangePosition(position);
}, [position, onChangePosition]);
return ( return (
<Box <Box
className="KT-draggable" className="KT-draggable"

View File

@@ -14,6 +14,8 @@ import UnfoldLessIcon from "@mui/icons-material/UnfoldLess";
import UnfoldMoreIcon from "@mui/icons-material/UnfoldMore"; import UnfoldMoreIcon from "@mui/icons-material/UnfoldMore";
import PushPinIcon from "@mui/icons-material/PushPin"; import PushPinIcon from "@mui/icons-material/PushPin";
import PushPinOutlinedIcon from "@mui/icons-material/PushPinOutlined"; import PushPinOutlinedIcon from "@mui/icons-material/PushPinOutlined";
import LockIcon from "@mui/icons-material/Lock";
import LockOpenIcon from "@mui/icons-material/LockOpen";
import CloseIcon from "@mui/icons-material/Close"; import CloseIcon from "@mui/icons-material/Close";
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 } from "../../config";
@@ -30,6 +32,8 @@ function Header({
setSimpleStyle, setSimpleStyle,
hideClickAway, hideClickAway,
setHideClickAway, setHideClickAway,
followSelection,
setFollowSelection,
}) { }) {
return ( return (
<Box <Box
@@ -47,6 +51,18 @@ function Header({
}} }}
> >
{hideClickAway ? ( {hideClickAway ? (
<LockOpenIcon fontSize="small" />
) : (
<LockIcon fontSize="small" />
)}
</IconButton>
<IconButton
size="small"
onClick={() => {
setFollowSelection((pre) => !pre);
}}
>
{followSelection ? (
<PushPinOutlinedIcon fontSize="small" /> <PushPinOutlinedIcon fontSize="small" />
) : ( ) : (
<PushPinIcon fontSize="small" /> <PushPinIcon fontSize="small" />
@@ -243,14 +259,18 @@ export default function TranBox({
setSimpleStyle, setSimpleStyle,
hideClickAway, hideClickAway,
setHideClickAway, setHideClickAway,
followSelection,
setFollowSelection,
extStyles, extStyles,
}) { }) {
return ( return (
<SettingProvider> <SettingProvider>
<ThemeProvider styles={extStyles}> <ThemeProvider styles={extStyles}>
<DraggableResizable <DraggableResizable
defaultPosition={boxPosition} position={boxPosition}
defaultSize={boxSize} size={boxSize}
setSize={setBoxSize}
setPosition={setBoxPosition}
header={ header={
<Header <Header
setShowPopup={setShowBox} setShowPopup={setShowBox}
@@ -258,10 +278,10 @@ export default function TranBox({
setSimpleStyle={setSimpleStyle} setSimpleStyle={setSimpleStyle}
hideClickAway={hideClickAway} hideClickAway={hideClickAway}
setHideClickAway={setHideClickAway} setHideClickAway={setHideClickAway}
followSelection={followSelection}
setFollowSelection={setFollowSelection}
/> />
} }
onChangeSize={setBoxSize}
onChangePosition={setBoxPosition}
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
> >
<TranForm <TranForm

View File

@@ -25,6 +25,7 @@ export default function Slection({
hideTranBtn = false, hideTranBtn = false,
simpleStyle: initSimpleStyle = false, simpleStyle: initSimpleStyle = false,
hideClickAway: initHideClickAway = false, hideClickAway: initHideClickAway = false,
followSelection: initFollowMouse = false,
tranboxShortcut = DEFAULT_TRANBOX_SHORTCUT, tranboxShortcut = DEFAULT_TRANBOX_SHORTCUT,
triggerMode = OPT_TRANBOX_TRIGGER_CLICK, triggerMode = OPT_TRANBOX_TRIGGER_CLICK,
extStyles, extStyles,
@@ -55,6 +56,7 @@ export default function Slection({
}); });
const [simpleStyle, setSimpleStyle] = useState(initSimpleStyle); const [simpleStyle, setSimpleStyle] = useState(initSimpleStyle);
const [hideClickAway, setHideClickAway] = useState(initHideClickAway); const [hideClickAway, setHideClickAway] = useState(initHideClickAway);
const [followSelection, setFollowSelection] = useState(initFollowMouse);
const handleTrigger = useCallback( const handleTrigger = useCallback(
(text) => { (text) => {
@@ -68,16 +70,25 @@ export default function Slection({
const handleTranbox = useCallback(() => { const handleTranbox = useCallback(() => {
setShowBtn(false); setShowBtn(false);
const selectedText = window.getSelection()?.toString()?.trim() || ""; const selection = window.getSelection();
const selectedText = selection?.toString()?.trim() || "";
if (!selectedText) { if (!selectedText) {
setShowBox((pre) => !pre); setShowBox((pre) => !pre);
return; return;
} }
const rect = selection?.getRangeAt(0)?.getBoundingClientRect();
if (rect && followSelection) {
setBoxPosition({
x: limitNumber(rect.right, 0, window.innerWidth - 300),
y: limitNumber(rect.bottom, 0, window.innerHeight - 200),
});
}
setSelText(selectedText); setSelText(selectedText);
setText(selectedText); setText(selectedText);
setShowBox(true); setShowBox(true);
}, []); }, [followSelection]);
const btnEvent = useMemo(() => { const btnEvent = useMemo(() => {
if (isMobile) { if (isMobile) {
@@ -93,13 +104,22 @@ export default function Slection({
e.stopPropagation(); e.stopPropagation();
await sleep(200); await sleep(200);
const selectedText = window.getSelection()?.toString()?.trim() || ""; const selection = window.getSelection();
const selectedText = selection?.toString()?.trim() || "";
setSelText(selectedText); setSelText(selectedText);
if (!selectedText) { if (!selectedText) {
setShowBtn(false); setShowBtn(false);
return; return;
} }
const rect = selection?.getRangeAt(0)?.getBoundingClientRect();
if (rect && followSelection) {
setBoxPosition({
x: limitNumber(rect.right, 0, window.innerWidth - 300),
y: limitNumber(rect.bottom, 0, window.innerHeight - 200),
});
}
if (triggerMode === OPT_TRANBOX_TRIGGER_SELECT) { if (triggerMode === OPT_TRANBOX_TRIGGER_SELECT) {
handleTrigger(selectedText); handleTrigger(selectedText);
return; return;
@@ -119,7 +139,7 @@ export default function Slection({
handleMouseup handleMouseup
); );
}; };
}, [hideTranBtn, triggerMode, handleTrigger]); }, [hideTranBtn, triggerMode, followSelection, handleTrigger]);
useEffect(() => { useEffect(() => {
if (isExt) { if (isExt) {
@@ -196,6 +216,8 @@ export default function Slection({
setSimpleStyle={setSimpleStyle} setSimpleStyle={setSimpleStyle}
hideClickAway={hideClickAway} hideClickAway={hideClickAway}
setHideClickAway={setHideClickAway} setHideClickAway={setHideClickAway}
followSelection={followSelection}
setFollowSelection={setFollowSelection}
extStyles={extStyles} extStyles={extStyles}
/> />
)} )}