import Box from "@mui/material/Box"; import Stack from "@mui/material/Stack"; import TextField from "@mui/material/TextField"; import Button from "@mui/material/Button"; import { GLOBAL_KEY, DEFAULT_RULE, OPT_LANGS_FROM, OPT_LANGS_TO, OPT_TRANS_ALL, OPT_STYLE_ALL, BUILTIN_RULES, } from "../../config"; import { useState, useRef } from "react"; import { useI18n } from "../../hooks/I18n"; import Typography from "@mui/material/Typography"; import Accordion from "@mui/material/Accordion"; import AccordionSummary from "@mui/material/AccordionSummary"; import AccordionDetails from "@mui/material/AccordionDetails"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import { useRules } from "../../hooks/Rules"; import MenuItem from "@mui/material/MenuItem"; import Grid from "@mui/material/Grid"; import FileDownloadIcon from "@mui/icons-material/FileDownload"; import FileUploadIcon from "@mui/icons-material/FileUpload"; import { useSetting, useSettingUpdate } from "../../hooks/Setting"; import FormControlLabel from "@mui/material/FormControlLabel"; import Switch from "@mui/material/Switch"; function RuleFields({ rule, rules, setShow }) { const initFormValues = rule || { ...DEFAULT_RULE, transOpen: "true" }; const editMode = !!rule; const i18n = useI18n(); const [disabled, setDisabled] = useState(editMode); const [errors, setErrors] = useState({}); const [formValues, setFormValues] = useState(initFormValues); const { pattern, selector, translator, fromLang, toLang, textStyle, transOpen, bgColor, } = formValues; const hasSamePattern = (str) => { for (const item of rules.list) { if (item.pattern === str && rule?.pattern !== str) { return true; } } return false; }; const handleFocus = (e) => { e.preventDefault(); const { name } = e.target; setErrors((pre) => ({ ...pre, [name]: "" })); }; const handleChange = (e) => { e.preventDefault(); const { name, value } = e.target; setFormValues((pre) => ({ ...pre, [name]: value })); }; const handleCancel = (e) => { e.preventDefault(); if (editMode) { setDisabled(true); } else { setShow(false); } setErrors({}); setFormValues(initFormValues); }; const handleSubmit = (e) => { e.preventDefault(); const errors = {}; if (!pattern.trim()) { errors.pattern = i18n("error_cant_be_blank"); } if (hasSamePattern(pattern)) { errors.pattern = i18n("error_duplicate_values"); } if (pattern === "*" && !errors.pattern && !selector.trim()) { errors.selector = i18n("error_cant_be_blank"); } if (Object.keys(errors).length > 0) { setErrors(errors); return; } if (editMode) { // 编辑 setDisabled(true); rules.put(rule.pattern, formValues); } else { // 添加 rules.add(formValues); setShow(false); setFormValues(initFormValues); } }; const globalItem = rule?.pattern !== "*" && ( {GLOBAL_KEY} ); return (
{globalItem} {i18n("default_enabled")} {i18n("default_disabled")} {globalItem} {OPT_TRANS_ALL.map((item) => ( {item} ))} {globalItem} {OPT_LANGS_FROM.map(([lang, name]) => ( {name} ))} {globalItem} {OPT_LANGS_TO.map(([lang, name]) => ( {name} ))} {globalItem} {OPT_STYLE_ALL.map((item) => ( {i18n(item)} ))} {rules && (editMode ? ( // 编辑 {disabled ? ( <> {rule?.pattern !== "*" && ( )} ) : ( <> )} ) : ( // 添加 ))}
); } function RuleAccordion({ rule, rules }) { const [expanded, setExpanded] = useState(false); const handleChange = (e) => { setExpanded((pre) => !pre); }; return ( }> {rule.pattern} {expanded && } ); } function DownloadButton({ data, text, fileName }) { const handleClick = (e) => { e.preventDefault(); if (data) { const url = window.URL.createObjectURL(new Blob([data])); const link = document.createElement("a"); link.href = url; link.setAttribute("download", fileName || `${Date.now()}.json`); document.body.appendChild(link); link.click(); link.remove(); } }; return ( ); } function UploadButton({ onChange, text }) { const inputRef = useRef(null); const handleClick = () => { inputRef.current && inputRef.current.click(); }; return ( ); } export default function Rules() { const i18n = useI18n(); const rules = useRules(); const [showAdd, setShowAdd] = useState(false); const setting = useSetting(); const updateSetting = useSettingUpdate(); const injectRules = !!setting?.injectRules; const handleImport = (e) => { const file = e.target.files[0]; if (!file) { return; } if (!file.type.includes("json")) { alert(i18n("error_wrong_file_type")); return; } const reader = new FileReader(); reader.onload = async (e) => { try { await rules.merge(JSON.parse(e.target.result)); } catch (err) { console.log("[import rules]", err); } }; reader.readAsText(file); }; const handleInject = () => { updateSetting({ injectRules: !injectRules, }); }; return ( } label={i18n("inject_rules")} /> {showAdd && } {rules.list.map((rule) => ( ))} {injectRules && ( {BUILTIN_RULES.map((rule) => ( ))} )} ); }