tranbox...

This commit is contained in:
Gabe Yuan
2023-10-23 18:02:42 +08:00
parent e89da9120c
commit 4125aba808
13 changed files with 706 additions and 21 deletions

View File

@@ -0,0 +1,248 @@
import { useState } from "react";
import Paper from "@mui/material/Paper";
import Box from "@mui/material/Box";
function Pointer({
direction,
size,
setSize,
position,
setPosition,
children,
minSize,
maxSize,
...props
}) {
const [origin, setOrigin] = useState(null);
function handlePointerDown(e) {
e.target.setPointerCapture(e.pointerId);
setOrigin({
x: position.x,
y: position.y,
w: size.w,
h: size.h,
clientX: e.clientX,
clientY: e.clientY,
});
}
function handlePointerMove(e) {
if (origin) {
const dx = e.clientX - origin.clientX;
const dy = e.clientY - origin.clientY;
let x = position.x;
let y = position.y;
let w = size.w;
let h = size.h;
switch (direction) {
case "Header":
x = origin.x + dx;
y = origin.y + dy;
break;
case "TopLeft":
x = origin.x + dx;
y = origin.y + dy;
w = origin.w - dx;
h = origin.h - dy;
break;
case "Top":
y = origin.y + dy;
h = origin.h - dy;
break;
case "TopRight":
y = origin.y + dy;
w = origin.w + dx;
h = origin.h - dy;
break;
case "Left":
x = origin.x + dx;
w = origin.w - dx;
break;
case "Right":
w = origin.w + dx;
break;
case "BottomLeft":
x = origin.x + dx;
w = origin.w - dx;
h = origin.h + dy;
break;
case "Bottom":
h = origin.h + dy;
break;
case "BottomRight":
w = origin.w + dx;
h = origin.h + dy;
break;
}
if (w < minSize.w) {
w = minSize.w;
x = position.x;
}
if (w > maxSize.w) {
w = maxSize.w;
x = position.x;
}
if (h < minSize.h) {
h = minSize.h;
y = position.y;
}
if (h > maxSize.h) {
h = maxSize.h;
y = position.y;
}
setPosition({ x, y });
setSize({ w, h });
}
}
function handlePointerUp(e) {
setOrigin(null);
}
return (
<div
{...props}
onPointerDown={handlePointerDown}
onPointerMove={handlePointerMove}
onPointerUp={handlePointerUp}
>
{children}
</div>
);
}
export default function DraggableResizable({
header,
children,
defaultPosition = {
x: 0,
y: 0,
},
defaultSize = {
w: 600,
h: 400,
},
minSize = {
w: 300,
h: 200,
},
maxSize = {
w: 1200,
h: 1200,
},
sx,
}) {
const lineWidth = 4;
const [position, setPosition] = useState(defaultPosition);
const [size, setSize] = useState(defaultSize);
const opts = {
size,
setSize,
position,
setPosition,
minSize,
maxSize,
};
return (
<Box
style={{
position: "fixed",
left: position.x,
top: position.y,
display: "grid",
gridTemplateColumns: `${lineWidth * 2}px auto ${lineWidth * 2}px`,
gridTemplateRows: `${lineWidth * 2}px auto ${lineWidth * 2}px`,
zIndex: 10000,
}}
>
<Pointer
direction="TopLeft"
style={{
transform: `translate(${lineWidth}px, ${lineWidth}px)`,
cursor: "nw-resize",
}}
{...opts}
/>
<Pointer
direction="Top"
style={{
margin: `0 ${lineWidth}px`,
transform: `translate(0px, ${lineWidth}px)`,
cursor: "row-resize",
}}
{...opts}
/>
<Pointer
direction="TopRight"
style={{
transform: `translate(-${lineWidth}px, ${lineWidth}px)`,
cursor: "ne-resize",
}}
{...opts}
/>
<Pointer
direction="Left"
style={{
margin: `${lineWidth}px 0`,
transform: `translate(${lineWidth}px, 0px)`,
cursor: "col-resize",
}}
{...opts}
/>
<Paper elevation={4}>
<Pointer direction="Header" style={{ cursor: "move" }} {...opts}>
{header}
</Pointer>
<div
style={{
width: size.w,
height: size.h,
overflow: "hidden auto",
}}
>
{children}
</div>
</Paper>
<Pointer
direction="Right"
style={{
margin: `${lineWidth}px 0`,
transform: `translate(-${lineWidth}px, 0px)`,
cursor: "col-resize",
}}
{...opts}
/>
<Pointer
direction="BottomLeft"
style={{
transform: `translate(${lineWidth}px, -${lineWidth}px)`,
cursor: "ne-resize",
}}
{...opts}
/>
<Pointer
direction="Bottom"
style={{
margin: `0 ${lineWidth}px`,
transform: `translate(0px, -${lineWidth}px)`,
cursor: "row-resize",
}}
{...opts}
/>
<Pointer
direction="BottomRight"
style={{
transform: `translate(-${lineWidth}px, -${lineWidth}px)`,
cursor: "nw-resize",
}}
{...opts}
/>
</Box>
);
}

View File

@@ -0,0 +1,105 @@
import { SettingProvider } from "../../hooks/Setting";
import ThemeProvider from "../../hooks/Theme";
import DraggableResizable from "./DraggableResizable";
import Header from "../Popup/Header";
import Stack from "@mui/material/Stack";
import TextField from "@mui/material/TextField";
import MenuItem from "@mui/material/MenuItem";
import Grid from "@mui/material/Grid";
import Box from "@mui/material/Box";
import Divider from "@mui/material/Divider";
import { useI18n } from "../../hooks/I18n";
import { OPT_TRANS_ALL, OPT_LANGS_FROM, OPT_LANGS_TO } from "../../config";
function TranForm({ tranboxSetting }) {
const i18n = useI18n();
const {
transOpen,
translator,
fromLang,
toLang,
tranboxShortcut,
btnOffsetX,
btnOffsetY,
} = tranboxSetting;
return (
<Stack sx={{ p: 2 }} spacing={2}>
<Box>
<Grid container spacing={2} columns={12}>
<Grid item xs={4} sm={4} md={4} lg={4}>
<TextField
select
SelectProps={{ MenuProps: { disablePortal: true } }}
fullWidth
size="small"
name="fromLang"
value={fromLang}
label={i18n("from_lang")}
// onChange={handleChange}
>
{OPT_LANGS_FROM.map(([lang, name]) => (
<MenuItem key={lang} value={lang}>
{name}
</MenuItem>
))}
</TextField>
</Grid>
<Grid item xs={4} sm={4} md={4} lg={4}>
<TextField
select
SelectProps={{ MenuProps: { disablePortal: true } }}
fullWidth
size="small"
name="toLang"
value={toLang}
label={i18n("to_lang")}
// onChange={handleChange}
>
{OPT_LANGS_TO.map(([lang, name]) => (
<MenuItem key={lang} value={lang}>
{name}
</MenuItem>
))}
</TextField>
</Grid>
<Grid item xs={4} sm={4} md={4} lg={4}>
<TextField
select
SelectProps={{ MenuProps: { disablePortal: true } }}
fullWidth
size="small"
value={translator}
name="translator"
label={i18n("translate_service")}
// onChange={handleChange}
>
{OPT_TRANS_ALL.map((item) => (
<MenuItem key={item} value={item}>
{item}
</MenuItem>
))}
</TextField>
</Grid>
</Grid>
</Box>
</Stack>
);
}
export default function TranBox({ position, setShowBox, tranboxSetting }) {
return (
<SettingProvider>
<ThemeProvider>
<DraggableResizable
defaultPosition={position}
header={<Header setShowPopup={setShowBox} />}
>
<Divider />
<TranForm tranboxSetting={tranboxSetting} />
</DraggableResizable>
</ThemeProvider>
</SettingProvider>
);
}

View File

@@ -0,0 +1,43 @@
export default function TranBtn({ onClick, position, tranboxSetting }) {
return (
<div
style={{
cursor: "pointer",
position: "fixed",
left: position.x + tranboxSetting.btnOffsetX,
top: position.y + tranboxSetting.btnOffsetY,
}}
onClick={onClick}
onMouseUp={(e) => {
e.stopPropagation();
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 32 32"
version="1.1"
>
<path
d="M 0.455 1.257 C 0.173 1.991, 0.068 9.096, 0.221 17.046 L 0.500 31.500 15.365 31.777 C 25.475 31.966, 30.672 31.687, 31.615 30.905 C 32.681 30.020, 33 26.349, 33 14.967 L 33 0.180 16.984 0.050 C 4.455 -0.051, 0.856 0.212, 0.455 1.257 M 0.402 16 C 0.402 24.525, 0.556 28.013, 0.743 23.750 C 0.931 19.488, 0.931 12.513, 0.743 8.250 C 0.556 3.988, 0.402 7.475, 0.402 16 M 3 16 C 3 26.333, 3.121 27, 5 27 C 6.681 27, 7 26.333, 7 22.826 L 7 18.651 9.500 21 C 10.875 22.292, 12 24.170, 12 25.174 C 12 26.333, 12.730 27, 14 27 C 17.333 27, 16.670 21.670, 12.978 18.780 L 9.957 16.415 12.978 13.521 C 14.640 11.928, 16 10.004, 16 9.243 C 16 8.382, 16.848 7.981, 18.250 8.180 C 20.374 8.482, 20.516 9.020, 20.788 17.750 C 21.011 24.955, 21.390 27, 22.500 27 C 23.610 27, 23.989 24.955, 24.212 17.750 C 24.484 9.020, 24.626 8.482, 26.750 8.180 C 27.987 8.005, 29 7.217, 29 6.430 C 29 5.302, 27.205 5, 20.500 5 C 12.937 5, 12 5.201, 12 6.826 C 12 7.830, 10.875 9.708, 9.500 11 L 7 13.349 7 9.174 C 7 5.667, 6.681 5, 5 5 C 3.121 5, 3 5.667, 3 16"
stroke="none"
fill="#209cee"
fillRule="evenodd"
/>
<path
d="M 4 16 C 4 22.667, 4.394 27, 5 27 C 5.550 27, 6 25.200, 6 23 C 6 20.345, 6.446 19, 7.326 19 C 9.199 19, 13 23.286, 13 25.398 C 13 26.371, 13.562 26.979, 14.250 26.750 C 16.713 25.930, 16.145 22.745, 12.946 19.444 L 9.705 16.100 12.852 12.515 C 14.584 10.544, 16 8.558, 16 8.104 C 16 7.649, 17.125 7.492, 18.500 7.755 C 20.957 8.225, 21 8.396, 21 17.700 C 21 24.828, 21.309 27.064, 22.250 26.752 C 23.100 26.471, 23.592 23.401, 23.788 17.169 C 24.049 8.823, 24.251 8, 26.038 8 C 27.140 8, 28 7.323, 28 6.456 C 28 5.179, 26.699 4.953, 20.500 5.151 C 14.356 5.347, 13 5.683, 13 7.008 C 13 8.949, 7.650 14.316, 6.681 13.347 C 6.306 12.973, 6 10.942, 6 8.833 C 6 6.725, 5.550 5, 5 5 C 4.394 5, 4 9.333, 4 16"
stroke="none"
fill="#f5f9fc"
fillRule="evenodd"
/>
<path
d="M 3.378 16 C 3.378 22.325, 3.541 24.912, 3.739 21.750 C 3.937 18.587, 3.937 13.412, 3.739 10.250 C 3.541 7.087, 3.378 9.675, 3.378 16 M 6.175 8.691 C 6.079 10.996, 6.381 13.118, 6.847 13.405 C 8.295 14.300, 13.227 8.362, 12.708 6.349 C 12.289 4.723, 12.218 4.750, 12.116 6.576 C 12.052 7.717, 10.903 9.682, 9.563 10.941 L 7.126 13.230 6.738 8.865 L 6.349 4.500 6.175 8.691 M 15.333 5.667 C 15.700 6.033, 16.300 6.033, 16.667 5.667 C 17.033 5.300, 16.733 5, 16 5 C 15.267 5, 14.967 5.300, 15.333 5.667 M 28.079 6.583 C 28.127 7.748, 28.364 7.985, 28.683 7.188 C 28.972 6.466, 28.936 5.603, 28.604 5.271 C 28.272 4.939, 28.036 5.529, 28.079 6.583 M 16 7.500 C 16 7.775, 16.225 8, 16.500 8 C 16.775 8, 17 7.775, 17 7.500 C 17 7.225, 16.775 7, 16.500 7 C 16.225 7, 16 7.225, 16 7.500 M 20 8.500 C 20 8.775, 20.225 9, 20.500 9 C 20.775 9, 21 8.775, 21 8.500 C 21 8.225, 20.775 8, 20.500 8 C 20.225 8, 20 8.225, 20 8.500 M 24 8.500 C 24 8.775, 24.225 9, 24.500 9 C 24.775 9, 25 8.775, 25 8.500 C 25 8.225, 24.775 8, 24.500 8 C 24.225 8, 24 8.225, 24 8.500 M 12.573 12.906 L 9.645 16.500 13.021 13.282 C 14.878 11.512, 16.196 9.895, 15.949 9.688 C 15.702 9.481, 14.183 10.929, 12.573 12.906 M 13.500 20 C 14.495 21.100, 15.535 22, 15.810 22 C 16.085 22, 15.495 21.100, 14.500 20 C 13.505 18.900, 12.465 18, 12.190 18 C 11.915 18, 12.505 18.900, 13.500 20 M 6.272 23 C 6.272 25.475, 6.467 26.488, 6.706 25.250 C 6.944 24.012, 6.944 21.988, 6.706 20.750 C 6.467 19.512, 6.272 20.525, 6.272 23 M 9.650 21 C 10.833 22.375, 12.018 24.400, 12.284 25.500 C 12.753 27.438, 12.772 27.436, 12.884 25.424 C 12.948 24.283, 11.762 22.258, 10.250 20.924 L 7.500 18.500 9.650 21 M 15 26.500 C 15 26.775, 15.225 27, 15.500 27 C 15.775 27, 16 26.775, 16 26.500 C 16 26.225, 15.775 26, 15.500 26 C 15.225 26, 15 26.225, 15 26.500 M 23 26.500 C 23 26.775, 23.225 27, 23.500 27 C 23.775 27, 24 26.775, 24 26.500 C 24 26.225, 23.775 26, 23.500 26 C 23.225 26, 23 26.225, 23 26.500"
stroke="none"
fill="#259cec"
fillRule="evenodd"
/>
</svg>
</div>
);
}

View File

@@ -0,0 +1,54 @@
import { useState, useEffect } from "react";
import TranBtn from "./Tranbtn";
import TranBox from "./Tranbox";
export default function Slection({ tranboxSetting }) {
const [showBox, setShowBox] = useState(false);
const [showBtn, setShowBtn] = useState(false);
const [text, setText] = useState("");
const [position, setPosition] = useState({ x: 0, y: 0 });
console.log("tranboxSetting", tranboxSetting);
function handleMouseup(e) {
const text = window.getSelection()?.toString()?.trim() || "";
setPosition({ x: e.clientX, y: e.clientY });
setText(text);
setShowBtn(!!text);
}
const handleClick = (e) => {
e.stopPropagation();
setShowBtn(false);
if (!!text) {
setShowBox(true);
}
};
useEffect(() => {
window.addEventListener("mouseup", handleMouseup);
return () => {
window.removeEventListener("mouseup", handleMouseup);
};
}, []);
return (
<>
{showBox && (
<TranBox
position={position}
tranboxSetting={tranboxSetting}
setShowBox={setShowBox}
/>
)}
{showBtn && (
<TranBtn
position={position}
tranboxSetting={tranboxSetting}
onClick={handleClick}
/>
)}
</>
);
}