userscript...
This commit is contained in:
72
src/views/Action/Draggable.js
Normal file
72
src/views/Action/Draggable.js
Normal file
@@ -0,0 +1,72 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { limitNumber } from "../../libs/utils";
|
||||
|
||||
export default function Draggable(props) {
|
||||
const [origin, setOrigin] = useState(null);
|
||||
const [position, setPosition] = useState({
|
||||
x: props.left,
|
||||
y: props.top,
|
||||
});
|
||||
|
||||
const handlePointerDown = (e) => {
|
||||
e.target.setPointerCapture(e.pointerId);
|
||||
props?.onStart();
|
||||
setOrigin({
|
||||
x: position.x,
|
||||
y: position.y,
|
||||
px: e.clientX,
|
||||
py: e.clientY,
|
||||
});
|
||||
};
|
||||
|
||||
const handlePointerMove = (e) => {
|
||||
props?.onMove();
|
||||
if (origin) {
|
||||
const dx = e.clientX - origin.px;
|
||||
const dy = e.clientY - origin.py;
|
||||
let x = origin.x + dx;
|
||||
let y = origin.y + dy;
|
||||
const { w, h } = props.windowSize;
|
||||
x = limitNumber(x, 0, w - props.width);
|
||||
y = limitNumber(y, 0, h - props.height);
|
||||
setPosition({ x, y });
|
||||
}
|
||||
};
|
||||
|
||||
const handlePointerUp = (e) => {
|
||||
setOrigin(null);
|
||||
};
|
||||
|
||||
const handleClick = (e) => {
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const { w, h } = props.windowSize;
|
||||
setPosition(({ x, y }) => ({
|
||||
x: limitNumber(x, 0, w - props.width),
|
||||
y: limitNumber(y, 0, h - props.height),
|
||||
}));
|
||||
}, [props.windowSize, props.width, props.height]);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: "fixed",
|
||||
left: position.x,
|
||||
top: position.y,
|
||||
zIndex: 2147483647,
|
||||
}}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<div
|
||||
onPointerDown={handlePointerDown}
|
||||
onPointerMove={handlePointerMove}
|
||||
onPointerUp={handlePointerUp}
|
||||
>
|
||||
{props.handler}
|
||||
</div>
|
||||
<div>{props.children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,16 +1,132 @@
|
||||
import Paper from "@mui/material/Paper";
|
||||
import Box from "@mui/material/Box";
|
||||
import Fab from "@mui/material/Fab";
|
||||
import AddIcon from "@mui/icons-material/Add";
|
||||
import ThemeProvider from "../../hooks/Theme";
|
||||
import Draggable from "./Draggable";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import CloseIcon from "@mui/icons-material/Close";
|
||||
import Stack from "@mui/material/Stack";
|
||||
import { useEffect, useState, useMemo, useCallback } from "react";
|
||||
import { StoragesProvider } from "../../hooks/Storage";
|
||||
import Popup from "../Popup";
|
||||
|
||||
export default function Action() {
|
||||
const fabWidth = 56;
|
||||
const [showPopup, setShowPopup] = useState(false);
|
||||
const [windowSize, setWindowSize] = useState({
|
||||
w: window.innerWidth,
|
||||
h: window.innerHeight,
|
||||
});
|
||||
const [moved, setMoved] = useState(false);
|
||||
|
||||
const handleWindowResize = (e) => {
|
||||
setWindowSize({
|
||||
w: window.innerWidth,
|
||||
h: window.innerHeight,
|
||||
});
|
||||
};
|
||||
|
||||
const handleWindowClick = (e) => {
|
||||
setShowPopup(false);
|
||||
};
|
||||
|
||||
const handleStart = useCallback(() => {
|
||||
setMoved(false);
|
||||
}, []);
|
||||
|
||||
const handleMove = useCallback(() => {
|
||||
setMoved(true);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("resize", handleWindowResize);
|
||||
window.addEventListener("click", handleWindowClick);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("resize", handleWindowResize);
|
||||
window.removeEventListener("click", handleWindowClick);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const popProps = useMemo(() => {
|
||||
const width = Math.min(windowSize.w, 300);
|
||||
const height = Math.min(windowSize.h, 386);
|
||||
const left = (windowSize.w - width) / 2;
|
||||
const top = (windowSize.h - height) / 2;
|
||||
return {
|
||||
windowSize,
|
||||
width,
|
||||
height,
|
||||
left,
|
||||
top,
|
||||
};
|
||||
}, [windowSize]);
|
||||
|
||||
const fabProps = {
|
||||
windowSize,
|
||||
width: fabWidth,
|
||||
height: fabWidth,
|
||||
left: window.innerWidth - fabWidth - fabWidth,
|
||||
top: window.innerHeight - fabWidth - fabWidth,
|
||||
};
|
||||
|
||||
return (
|
||||
<ThemeProvider>
|
||||
<Box style={{ position: "fixed", top: 16, right: 16, zIndex: 10001 }}>
|
||||
<Fab color="primary">
|
||||
<AddIcon />
|
||||
</Fab>
|
||||
</Box>
|
||||
</ThemeProvider>
|
||||
<StoragesProvider>
|
||||
<ThemeProvider>
|
||||
{showPopup ? (
|
||||
<Draggable
|
||||
key="pop"
|
||||
{...popProps}
|
||||
onStart={handleStart}
|
||||
onMove={handleMove}
|
||||
handler={
|
||||
<Paper style={{ cursor: "move" }} elevation={3}>
|
||||
<Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
alignItems="center"
|
||||
spacing={2}
|
||||
>
|
||||
<Box style={{ marginLeft: 16 }}>
|
||||
{process.env.REACT_APP_NAME}
|
||||
</Box>
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
setShowPopup(false);
|
||||
}}
|
||||
>
|
||||
<CloseIcon />
|
||||
</IconButton>
|
||||
</Stack>
|
||||
</Paper>
|
||||
}
|
||||
>
|
||||
<Paper>
|
||||
<Popup />
|
||||
</Paper>
|
||||
</Draggable>
|
||||
) : (
|
||||
<Draggable
|
||||
key="fab"
|
||||
{...fabProps}
|
||||
onStart={handleStart}
|
||||
onMove={handleMove}
|
||||
handler={
|
||||
<Fab
|
||||
color="primary"
|
||||
onClick={(e) => {
|
||||
if (!moved) {
|
||||
setShowPopup((pre) => !pre);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<AddIcon />
|
||||
</Fab>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</ThemeProvider>
|
||||
</StoragesProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,13 +5,15 @@ import { useI18n, useI18nMd } from "../../hooks/I18n";
|
||||
|
||||
export default function About() {
|
||||
const i18n = useI18n();
|
||||
const [md, loading, error] = useI18nMd("about_md");
|
||||
const [data, loading, error] = useI18nMd("about_md");
|
||||
return (
|
||||
<Box>
|
||||
{loading ? (
|
||||
<CircularProgress />
|
||||
<center>
|
||||
<CircularProgress />
|
||||
</center>
|
||||
) : (
|
||||
<ReactMarkdown children={error ? i18n("about_md_local") : md} />
|
||||
<ReactMarkdown children={error ? i18n("about_md_local") : data} />
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
|
||||
@@ -6,7 +6,7 @@ import FormControlLabel from "@mui/material/FormControlLabel";
|
||||
import Switch from "@mui/material/Switch";
|
||||
import Button from "@mui/material/Button";
|
||||
import { sendTabMsg } from "../../libs/msg";
|
||||
import { browser } from "../../libs/browser";
|
||||
import { browser, isExt } from "../../libs/browser";
|
||||
import { useI18n } from "../../hooks/I18n";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import {
|
||||
@@ -17,6 +17,8 @@ import {
|
||||
OPT_LANGS_FROM,
|
||||
OPT_LANGS_TO,
|
||||
OPT_STYLE_ALL,
|
||||
EVENT_KISS,
|
||||
MSG_TRANS_CURRULE,
|
||||
} from "../../config";
|
||||
|
||||
export default function Popup() {
|
||||
@@ -24,13 +26,28 @@ export default function Popup() {
|
||||
const [rule, setRule] = useState(null);
|
||||
|
||||
const handleOpenSetting = () => {
|
||||
browser?.runtime.openOptionsPage();
|
||||
if (isExt) {
|
||||
browser?.runtime.openOptionsPage();
|
||||
} else {
|
||||
window.open(process.env.REACT_APP_OPTIONSPAGE, "_blank");
|
||||
}
|
||||
};
|
||||
|
||||
const handleTransToggle = async (e) => {
|
||||
try {
|
||||
setRule({ ...rule, transOpen: e.target.checked });
|
||||
await sendTabMsg(MSG_TRANS_TOGGLE);
|
||||
|
||||
if (isExt) {
|
||||
await sendTabMsg(MSG_TRANS_TOGGLE);
|
||||
} else {
|
||||
window.dispatchEvent(
|
||||
new CustomEvent(EVENT_KISS, {
|
||||
detail: {
|
||||
action: MSG_TRANS_TOGGLE,
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("[toggle trans]", err);
|
||||
}
|
||||
@@ -40,13 +57,50 @@ export default function Popup() {
|
||||
try {
|
||||
const { name, value } = e.target;
|
||||
setRule((pre) => ({ ...pre, [name]: value }));
|
||||
await sendTabMsg(MSG_TRANS_PUTRULE, { [name]: value });
|
||||
|
||||
if (isExt) {
|
||||
await sendTabMsg(MSG_TRANS_PUTRULE, { [name]: value });
|
||||
} else {
|
||||
window.dispatchEvent(
|
||||
new CustomEvent(EVENT_KISS, {
|
||||
detail: {
|
||||
action: MSG_TRANS_PUTRULE,
|
||||
args: { [name]: value },
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("[update rule]", err);
|
||||
}
|
||||
};
|
||||
|
||||
const handleKissEvent = (e) => {
|
||||
const action = e?.detail?.action;
|
||||
const args = e?.detail?.args || {};
|
||||
switch (action) {
|
||||
case MSG_TRANS_CURRULE:
|
||||
setRule(args);
|
||||
break;
|
||||
default:
|
||||
// console.log(`[popup] kissEvent action skip: ${action}`);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!isExt) {
|
||||
window.addEventListener(EVENT_KISS, handleKissEvent);
|
||||
window.dispatchEvent(
|
||||
new CustomEvent(EVENT_KISS, {
|
||||
detail: { action: MSG_TRANS_GETRULE },
|
||||
})
|
||||
);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener(EVENT_KISS, handleKissEvent);
|
||||
};
|
||||
}
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const res = await sendTabMsg(MSG_TRANS_GETRULE);
|
||||
@@ -75,7 +129,7 @@ export default function Popup() {
|
||||
|
||||
return (
|
||||
<Box minWidth={300} sx={{ p: 2 }}>
|
||||
<Stack spacing={3}>
|
||||
<Stack spacing={2}>
|
||||
<FormControlLabel
|
||||
control={<Switch checked={transOpen} onChange={handleTransToggle} />}
|
||||
label={i18n("translate")}
|
||||
@@ -83,6 +137,7 @@ export default function Popup() {
|
||||
|
||||
<TextField
|
||||
select
|
||||
SelectProps={{ MenuProps: { disablePortal: true } }}
|
||||
size="small"
|
||||
value={translator}
|
||||
name="translator"
|
||||
@@ -98,6 +153,7 @@ export default function Popup() {
|
||||
|
||||
<TextField
|
||||
select
|
||||
SelectProps={{ MenuProps: { disablePortal: true } }}
|
||||
size="small"
|
||||
value={fromLang}
|
||||
name="fromLang"
|
||||
@@ -113,6 +169,7 @@ export default function Popup() {
|
||||
|
||||
<TextField
|
||||
select
|
||||
SelectProps={{ MenuProps: { disablePortal: true } }}
|
||||
size="small"
|
||||
value={toLang}
|
||||
name="toLang"
|
||||
@@ -128,6 +185,7 @@ export default function Popup() {
|
||||
|
||||
<TextField
|
||||
select
|
||||
SelectProps={{ MenuProps: { disablePortal: true } }}
|
||||
size="small"
|
||||
value={textStyle}
|
||||
name="textStyle"
|
||||
|
||||
Reference in New Issue
Block a user