204 lines
5.0 KiB
JavaScript
204 lines
5.0 KiB
JavaScript
import { useState, useEffect, useMemo } from "react";
|
|
import LoadingIcon from "./LoadingIcon";
|
|
import {
|
|
OPT_STYLE_LINE,
|
|
OPT_STYLE_DOTLINE,
|
|
OPT_STYLE_DASHLINE,
|
|
OPT_STYLE_WAVYLINE,
|
|
OPT_STYLE_DASHBOX,
|
|
OPT_STYLE_FUZZY,
|
|
OPT_STYLE_HIGHLIGHT,
|
|
OPT_STYLE_BLOCKQUOTE,
|
|
OPT_STYLE_DIY,
|
|
DEFAULT_COLOR,
|
|
MSG_TRANS_CURRULE,
|
|
} from "../../config";
|
|
import { useTranslate } from "../../hooks/Translate";
|
|
import { styled, css } from "@mui/material/styles";
|
|
import { APP_LCNAME } from "../../config";
|
|
import interpreter from "../../libs/interpreter";
|
|
|
|
const LINE_STYLES = {
|
|
[OPT_STYLE_LINE]: "solid",
|
|
[OPT_STYLE_DOTLINE]: "dotted",
|
|
[OPT_STYLE_DASHLINE]: "dashed",
|
|
[OPT_STYLE_WAVYLINE]: "wavy",
|
|
};
|
|
|
|
const StyledSpan = styled("span")`
|
|
${({ textStyle, textDiyStyle, bgColor }) => {
|
|
switch (textStyle) {
|
|
case OPT_STYLE_LINE: // 下划线
|
|
case OPT_STYLE_DOTLINE: // 点状线
|
|
case OPT_STYLE_DASHLINE: // 虚线
|
|
case OPT_STYLE_WAVYLINE: // 波浪线
|
|
return css`
|
|
opacity: 0.6;
|
|
-webkit-opacity: 0.6;
|
|
text-decoration-line: underline;
|
|
text-decoration-style: ${LINE_STYLES[textStyle]};
|
|
text-decoration-color: ${bgColor};
|
|
text-decoration-thickness: 2px;
|
|
text-underline-offset: 0.3em;
|
|
-webkit-text-decoration-line: underline;
|
|
-webkit-text-decoration-style: ${LINE_STYLES[textStyle]};
|
|
-webkit-text-decoration-color: ${bgColor};
|
|
-webkit-text-decoration-thickness: 2px;
|
|
-webkit-text-underline-offset: 0.3em;
|
|
&:hover {
|
|
opacity: 1;
|
|
-webkit-opacity: 1;
|
|
}
|
|
`;
|
|
case OPT_STYLE_DASHBOX: // 虚线框
|
|
return css`
|
|
color: ${bgColor || DEFAULT_COLOR};
|
|
border: 1px dashed ${bgColor || DEFAULT_COLOR};
|
|
background: transparent;
|
|
display: block;
|
|
padding: 0.2em;
|
|
box-sizing: border-box;
|
|
white-space: normal;
|
|
word-wrap: break-word;
|
|
overflow-wrap: break-word;
|
|
`;
|
|
case OPT_STYLE_FUZZY: // 模糊
|
|
return css`
|
|
filter: blur(0.2em);
|
|
-webkit-filter: blur(0.2em);
|
|
&:hover {
|
|
filter: none;
|
|
-webkit-filter: none;
|
|
}
|
|
`;
|
|
case OPT_STYLE_HIGHLIGHT: // 高亮
|
|
return css`
|
|
color: #fff;
|
|
background-color: ${bgColor || DEFAULT_COLOR};
|
|
`;
|
|
case OPT_STYLE_BLOCKQUOTE: // 引用
|
|
return css`
|
|
opacity: 0.6;
|
|
-webkit-opacity: 0.6;
|
|
display: block;
|
|
padding: 0 0.75em;
|
|
border-left: 0.25em solid ${bgColor || DEFAULT_COLOR};
|
|
&:hover {
|
|
opacity: 1;
|
|
-webkit-opacity: 1;
|
|
}
|
|
`;
|
|
case OPT_STYLE_DIY: // 自定义
|
|
return textDiyStyle;
|
|
default:
|
|
return ``;
|
|
}
|
|
}}
|
|
`;
|
|
|
|
export default function Content({ q, keeps, translator, $el }) {
|
|
const [rule, setRule] = useState(translator.rule);
|
|
const { text, sameLang, loading } = useTranslate(q, rule, translator.setting);
|
|
const {
|
|
transOpen,
|
|
textStyle,
|
|
bgColor,
|
|
textDiyStyle,
|
|
transOnly,
|
|
transTag,
|
|
transEndHook,
|
|
} = rule;
|
|
|
|
const { newlineLength } = translator.setting;
|
|
|
|
const handleKissEvent = (e) => {
|
|
const { action, args } = e.detail;
|
|
switch (action) {
|
|
case MSG_TRANS_CURRULE:
|
|
setRule(args);
|
|
break;
|
|
default:
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
window.addEventListener(translator.eventName, handleKissEvent);
|
|
return () => {
|
|
window.removeEventListener(translator.eventName, handleKissEvent);
|
|
};
|
|
}, [translator.eventName]);
|
|
|
|
const gap = useMemo(() => {
|
|
if (transOnly === "true") {
|
|
return "";
|
|
}
|
|
return q.length >= newlineLength ? <br /> : " ";
|
|
}, [q, transOnly, newlineLength]);
|
|
|
|
const styles = useMemo(
|
|
() => ({
|
|
textStyle,
|
|
textDiyStyle,
|
|
bgColor,
|
|
as: transTag,
|
|
}),
|
|
[textStyle, textDiyStyle, bgColor, transTag]
|
|
);
|
|
|
|
const trText = useMemo(() => {
|
|
if (loading || !transEndHook?.trim()) {
|
|
return text;
|
|
}
|
|
|
|
// 翻译完成钩子函数
|
|
interpreter.run(`exports.transEndHook = ${transEndHook}`);
|
|
return interpreter.exports.transEndHook($el, text, q, keeps);
|
|
}, [loading, $el, q, text, keeps, transEndHook]);
|
|
|
|
if (loading) {
|
|
return (
|
|
<>
|
|
{gap}
|
|
<LoadingIcon />
|
|
</>
|
|
);
|
|
}
|
|
|
|
if (!trText || sameLang) {
|
|
return;
|
|
}
|
|
|
|
if (
|
|
transOnly === "true" &&
|
|
transOpen === "true" &&
|
|
$el.querySelector(APP_LCNAME)
|
|
) {
|
|
Array.from($el.childNodes).forEach((el) => {
|
|
if (el.localName !== APP_LCNAME) {
|
|
el.remove();
|
|
}
|
|
});
|
|
}
|
|
|
|
if (keeps.length > 0) {
|
|
return (
|
|
<>
|
|
{gap}
|
|
<StyledSpan
|
|
{...styles}
|
|
dangerouslySetInnerHTML={{
|
|
__html: trText.replace(/\[(\d+)\]/g, (_, p) => keeps[parseInt(p)]),
|
|
}}
|
|
/>
|
|
</>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<>
|
|
{gap}
|
|
<StyledSpan {...styles}>{trText}</StyledSpan>
|
|
</>
|
|
);
|
|
}
|