feat: transbox follow selection
This commit is contained in:
@@ -861,4 +861,8 @@ export const I18N = {
|
|||||||
zh: `打开设置`,
|
zh: `打开设置`,
|
||||||
en: `Open Setting`,
|
en: `Open Setting`,
|
||||||
},
|
},
|
||||||
|
follow_selection: {
|
||||||
|
zh: `翻译框跟随选中文本`,
|
||||||
|
en: `Transbox Follow Selection`,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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: "", // 附加样式
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user