This commit is contained in:
Gabe Yuan
2023-08-10 09:30:43 +08:00
6 changed files with 102 additions and 44 deletions

3
.env
View File

@@ -6,3 +6,6 @@ REACT_APP_HOMEPAGE=https://github.com/fishjar/kiss-translator
REACT_APP_OPTIONSPAGE=https://kiss-translator.rayjar.com/options REACT_APP_OPTIONSPAGE=https://kiss-translator.rayjar.com/options
REACT_APP_OPTIONSPAGE2=https://fishjar.github.io/kiss-translator/options.html REACT_APP_OPTIONSPAGE2=https://fishjar.github.io/kiss-translator/options.html
REACT_APP_OPTIONSPAGE_DEV=http://localhost:3000/options.html REACT_APP_OPTIONSPAGE_DEV=http://localhost:3000/options.html
REACT_APP_LOGOURL=https://raw.githubusercontent.com/fishjar/kiss-translator/master/public/images/logo192.png
REACT_APP_USERSCRIPT_DOWNLOADURL=https://kiss-translator.rayjar.com/kiss-translator.user.js
REACT_APP_USERSCRIPT_DOWNLOADURL2=https://raw.githubusercontent.com/fishjar/kiss-translator/master/dist/userscript/kiss-translator.user.js

View File

@@ -79,9 +79,9 @@ const userscriptWebpack = (config, env) => {
// @author Gabe<yugang2002@gmail.com> // @author Gabe<yugang2002@gmail.com>
// @homepageURL ${process.env.REACT_APP_HOMEPAGE} // @homepageURL ${process.env.REACT_APP_HOMEPAGE}
// @match *://*/* // @match *://*/*
// @icon https://raw.githubusercontent.com/fishjar/kiss-translator/master/public/images/logo192.png // @icon ${process.env.REACT_APP_LOGOURL}
// @downloadURL https://raw.githubusercontent.com/fishjar/kiss-translator/master/dist/userscript/kiss-translator.user.js // @downloadURL ${process.env.REACT_APP_USERSCRIPT_DOWNLOADURL}
// @updateURL https://raw.githubusercontent.com/fishjar/kiss-translator/master/dist/userscript/kiss-translator.user.js // @updateURL ${process.env.REACT_APP_USERSCRIPT_DOWNLOADURL}
// @grant GM_xmlhttpRequest // @grant GM_xmlhttpRequest
// @grant GM.xmlhttpRequest // @grant GM.xmlhttpRequest
// @grant GM_setValue // @grant GM_setValue

View File

@@ -1,17 +1,59 @@
import { useEffect, useState } from "react"; import { useEffect, useMemo, useState } from "react";
import { limitNumber } from "../../libs/utils"; import { limitNumber } from "../../libs/utils";
import { isMobile } from "../../libs/mobile"; import { isMobile } from "../../libs/mobile";
export default function Draggable(props) { const getSidePosition = (
const [origin, setOrigin] = useState(null); windowWidth,
windowHeight,
width,
height,
left,
top
) => {
const right = Math.abs(windowWidth - left - width);
const bottom = Math.abs(windowHeight - top - height);
left = Math.abs(left);
top = Math.abs(top);
const min = Math.min(left, top, right, bottom);
switch (min) {
case right:
left = windowWidth - width / 2;
break;
case left:
left = -width / 2;
break;
case bottom:
top = windowHeight - height / 2;
break;
default:
top = -height / 2;
}
return { x: left, y: top };
};
export default function Draggable({
windowSize,
width,
height,
left,
top,
show,
goside,
onStart,
onMove,
handler,
children,
}) {
const [origin, setOrigin] = useState(goside ? {} : null);
const [position, setPosition] = useState({ const [position, setPosition] = useState({
x: props.left, x: left,
y: props.top, y: top,
}); });
const handlePointerDown = (e) => { const handlePointerDown = (e) => {
!isMobile && e.target.setPointerCapture(e.pointerId); !isMobile && e.target.setPointerCapture(e.pointerId);
props?.onStart(); onStart && onStart();
const { clientX, clientY } = isMobile ? e.targetTouches[0] : e; const { clientX, clientY } = isMobile ? e.targetTouches[0] : e;
setOrigin({ setOrigin({
x: position.x, x: position.x,
@@ -22,37 +64,28 @@ export default function Draggable(props) {
}; };
const handlePointerMove = (e) => { const handlePointerMove = (e) => {
props?.onMove(); onMove && onMove();
const { clientX, clientY } = isMobile ? e.targetTouches[0] : e; const { clientX, clientY } = isMobile ? e.targetTouches[0] : e;
if (origin) { if (origin) {
const dx = clientX - origin.px; const dx = clientX - origin.px;
const dy = clientY - origin.py; const dy = clientY - origin.py;
let x = origin.x + dx; let x = origin.x + dx;
let y = origin.y + dy; let y = origin.y + dy;
const { w, h } = props.windowSize; const { w, h } = windowSize;
x = limitNumber(x, -props.width / 2, w - props.width / 2); x = limitNumber(x, -width / 2, w - width / 2);
y = limitNumber(y, -props.height / 2, h - props.height / 2); y = limitNumber(y, -height / 2, h - height / 2);
setPosition({ x, y }); setPosition({ x, y });
} }
}; };
const handlePointerUp = (e) => { const handlePointerUp = (e) => {
setOrigin(null); setOrigin(null);
if (!goside) {
if (!props.goside) {
return; return;
} }
setPosition((pre) =>
const { w, h } = props.windowSize; getSidePosition(windowSize.w, windowSize.h, width, height, pre.x, pre.y)
let { x: left, y: top } = position; );
const right = w - left - props.width;
const bottom = h - top - props.height;
const min = Math.min(left, top, right, bottom);
left === min && (left = -props.width / 2);
top === min && (top = -props.height / 2);
right === min && (left = w - props.width / 2);
bottom === min && (top = h - props.height / 2);
setPosition({ x: left, y: top });
}; };
const handleClick = (e) => { const handleClick = (e) => {
@@ -72,23 +105,33 @@ export default function Draggable(props) {
}; };
useEffect(() => { useEffect(() => {
const { w, h } = props.windowSize; setOrigin(null);
setPosition(({ x, y }) => ({ if (!goside) {
x: limitNumber(x, -props.width / 2, w - props.width / 2), return;
y: limitNumber(y, -props.height / 2, h - props.height / 2), }
})); setPosition((pre) =>
}, [props.windowSize, props.width, props.height]); getSidePosition(windowSize.w, windowSize.h, width, height, pre.x, pre.y)
);
}, [goside, windowSize.w, windowSize.h, width, height]);
const opacity = useMemo(() => {
if (goside) {
return origin ? 1 : 0.3;
}
return origin ? 0.7 : 1;
}, [origin, goside]);
return ( return (
<div <div
style={{ style={{
opacity,
position: "fixed", position: "fixed",
left: position.x, left: position.x,
top: position.y, top: position.y,
zIndex: 2147483647, zIndex: 2147483647,
display: props.show ? "block" : "none", display: show ? "block" : "none",
transitionProperty: origin ? "none" : "all", transitionProperty: origin ? "none" : "all",
transitionDuration: "1s", transitionDuration: "0.5s",
transitionDelay: "0.5s", transitionDelay: "0.5s",
}} }}
onClick={handleClick} onClick={handleClick}
@@ -99,9 +142,9 @@ export default function Draggable(props) {
}} }}
{...touchProps} {...touchProps}
> >
{props.handler} {handler}
</div> </div>
<div>{props.children}</div> <div>{children}</div>
</div> </div>
); );
} }

View File

@@ -51,7 +51,7 @@ export default function Action({ translator }) {
const popProps = useMemo(() => { const popProps = useMemo(() => {
const width = Math.min(windowSize.w, 300); const width = Math.min(windowSize.w, 300);
const height = Math.min(windowSize.h, 386); const height = Math.min(windowSize.h, 442);
const left = (windowSize.w - width) / 2; const left = (windowSize.w - width) / 2;
const top = (windowSize.h - height) / 2; const top = (windowSize.h - height) / 2;
return { return {
@@ -67,8 +67,8 @@ export default function Action({ translator }) {
windowSize, windowSize,
width: fabWidth, width: fabWidth,
height: fabWidth, height: fabWidth,
left: window.innerWidth - fabWidth - fabWidth / 2, left: window.innerWidth - fabWidth,
top: window.innerHeight - fabWidth - fabWidth, top: window.innerHeight / 2,
}; };
return ( return (

View File

@@ -9,6 +9,7 @@ import ThemeProvider from "../../hooks/Theme";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { isGm } from "../../libs/browser"; import { isGm } from "../../libs/browser";
import { sleep } from "../../libs/utils"; import { sleep } from "../../libs/utils";
import CircularProgress from "@mui/material/CircularProgress";
export default function Options() { export default function Options() {
const [error, setError] = useState(false); const [error, setError] = useState(false);
@@ -22,7 +23,6 @@ export default function Options() {
(async () => { (async () => {
let i = 0; let i = 0;
for (;;) { for (;;) {
await sleep(1000);
if (window.APP_NAME === process.env.REACT_APP_NAME) { if (window.APP_NAME === process.env.REACT_APP_NAME) {
setReady(true); setReady(true);
break; break;
@@ -32,6 +32,8 @@ export default function Options() {
setError(true); setError(true);
break; break;
} }
await sleep(1000);
} }
})(); })();
}, []); }, []);
@@ -41,11 +43,13 @@ export default function Options() {
<center> <center>
<h2> <h2>
Please confirm whether to install or enable{" "} Please confirm whether to install or enable{" "}
<a href={process.env.REACT_APP_OPTIONSPAGE}>KISS Translator</a>{" "} <a href={process.env.REACT_APP_HOMEPAGE}>KISS Translator</a>{" "}
GreaseMonkey script? GreaseMonkey script?
</h2> </h2>
<h2> <h2>
or <a href={process.env.REACT_APP_HOMEPAGE}>click here</a> for help <a href={process.env.REACT_APP_USERSCRIPT_DOWNLOADURL}>Click here</a>{" "}
to install, or <a href={process.env.REACT_APP_HOMEPAGE}>click here</a>{" "}
for help.
</h2> </h2>
</center> </center>
); );
@@ -54,7 +58,7 @@ export default function Options() {
if (isGm && !ready) { if (isGm && !ready) {
return ( return (
<center> <center>
<h2>loading...</h2> <CircularProgress />
</center> </center>
); );
} }

View File

@@ -89,7 +89,7 @@ export default function Popup({ setShowPopup, translator: tran }) {
); );
} }
const { transOpen, translator, fromLang, toLang, textStyle } = rule; const { transOpen, translator, fromLang, toLang, textStyle, bgColor } = rule;
return ( return (
<Box minWidth={300} sx={{ p: 2 }}> <Box minWidth={300} sx={{ p: 2 }}>
@@ -168,6 +168,14 @@ export default function Popup({ setShowPopup, translator: tran }) {
))} ))}
</TextField> </TextField>
<TextField
size="small"
name="bgColor"
defaultValue={bgColor}
label={i18n("bg_color")}
onBlur={handleChange}
/>
<Button variant="text" onClick={handleOpenSetting}> <Button variant="text" onClick={handleOpenSetting}>
{i18n("setting")} {i18n("setting")}
</Button> </Button>