Pārlūkot izejas kodu

fix: no snippets and warnings in runtime config editor

dongchengjie 1 gadu atpakaļ
vecāks
revīzija
1809cdbf37

+ 21 - 8
src/components/profile/editor-viewer.tsx

@@ -1,4 +1,4 @@
-import { useEffect, useRef } from "react";
+import { ReactNode, useEffect, useRef } from "react";
 import { useLockFn } from "ahooks";
 import { useRecoilValue } from "recoil";
 import { useTranslation } from "react-i18next";
@@ -24,9 +24,11 @@ import mergeSchema from "meta-json-schema/schemas/clash-verge-merge-json-schema.
 import pac from "types-pac/pac.d.ts?raw";
 
 interface Props {
+  title?: string | ReactNode;
   mode: "profile" | "text";
   property: string;
   open: boolean;
+  readOnly?: boolean;
   language: "yaml" | "javascript" | "css";
   schema?: "clash" | "merge";
   onClose: () => void;
@@ -56,7 +58,17 @@ configureMonacoYaml(monaco, {
 monaco.languages.typescript.javascriptDefaults.addExtraLib(pac, "pac.d.ts");
 
 export const EditorViewer = (props: Props) => {
-  const { mode, property, open, language, schema, onClose, onChange } = props;
+  const {
+    title,
+    mode,
+    property,
+    open,
+    readOnly,
+    language,
+    schema,
+    onClose,
+    onChange,
+  } = props;
   const { t } = useTranslation();
   const editorRef = useRef<any>();
   const instanceRef = useRef<editor.IStandaloneCodeEditor | null>(null);
@@ -86,10 +98,13 @@ export const EditorViewer = (props: Props) => {
       instanceRef.current = editor.create(editorRef.current, {
         model: model,
         language: language,
-        tabSize: ["yaml", "javascript", "css"].includes(language) ? 2 : 4, // 根据语言类型设置缩进
+        tabSize: ["yaml", "javascript", "css"].includes(language) ? 2 : 4, // 根据语言类型设置缩进大小
         theme: themeMode === "light" ? "vs" : "vs-dark",
         minimap: { enabled: dom.clientWidth >= 1000 }, // 超过一定宽度显示minimap滚动条
-        mouseWheelZoom: true, // Ctrl+滚轮调节缩放
+        mouseWheelZoom: true, // 按住Ctrl滚轮调节缩放比例
+        readOnly: readOnly, // 只读模式
+        readOnlyMessage: { value: t("ReadOnlyMessage") }, // 只读模式尝试编辑时的提示信息
+        renderValidationDecorations: "on", // 只读模式下显示校验信息
         quickSuggestions: {
           strings: true, // 字符串类型的建议
           comments: true, // 注释类型的建议
@@ -129,11 +144,9 @@ export const EditorViewer = (props: Props) => {
 
   return (
     <Dialog open={open} onClose={onClose} maxWidth="xl" fullWidth>
-      <DialogTitle>{t("Edit File")}</DialogTitle>
+      <DialogTitle>{title ?? t("Edit File")}</DialogTitle>
 
-      <DialogContent
-        sx={{ width: "auto", height: "100vh", pb: 1, userSelect: "text" }}
-      >
+      <DialogContent sx={{ width: "auto", height: "100vh" }}>
         <div style={{ width: "100%", height: "100%" }} ref={editorRef} />
       </DialogContent>
 

+ 22 - 75
src/components/setting/mods/config-viewer.tsx

@@ -1,93 +1,40 @@
-import {
-  forwardRef,
-  useEffect,
-  useImperativeHandle,
-  useRef,
-  useState,
-} from "react";
+import { forwardRef, useImperativeHandle, useState } from "react";
 import { useTranslation } from "react-i18next";
-import { useRecoilValue } from "recoil";
-import {
-  Button,
-  Dialog,
-  DialogActions,
-  DialogContent,
-  DialogTitle,
-  Chip,
-} from "@mui/material";
-import { atomThemeMode } from "@/services/states";
+import { Box, Chip } from "@mui/material";
 import { getRuntimeYaml } from "@/services/cmds";
 import { DialogRef } from "@/components/base";
-import { editor } from "monaco-editor/esm/vs/editor/editor.api";
+import { EditorViewer } from "@/components/profile/editor-viewer";
 
-import "monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution.js";
-import "monaco-editor/esm/vs/basic-languages/yaml/yaml.contribution.js";
-import "monaco-editor/esm/vs/editor/contrib/folding/browser/folding.js";
-
-export const ConfigViewer = forwardRef<DialogRef>((props, ref) => {
+export const ConfigViewer = forwardRef<DialogRef>((_, ref) => {
   const { t } = useTranslation();
   const [open, setOpen] = useState(false);
-
-  const editorRef = useRef<any>();
-  const instanceRef = useRef<editor.IStandaloneCodeEditor | null>(null);
-  const themeMode = useRecoilValue(atomThemeMode);
-
-  useEffect(() => {
-    return () => {
-      if (instanceRef.current) {
-        instanceRef.current.dispose();
-        instanceRef.current = null;
-      }
-    };
-  }, []);
+  const [runtimeConfig, setRuntimeConfig] = useState("");
 
   useImperativeHandle(ref, () => ({
     open: () => {
-      setOpen(true);
-
       getRuntimeYaml().then((data) => {
-        const dom = editorRef.current;
-
-        if (!dom) return;
-        if (instanceRef.current) instanceRef.current.dispose();
-
-        instanceRef.current = editor.create(editorRef.current, {
-          value: data ?? "# Error\n",
-          language: "yaml",
-          tabSize: 2,
-          theme: themeMode === "light" ? "vs" : "vs-dark",
-          minimap: { enabled: dom.clientWidth >= 1000 }, // 超过一定宽度显示minimap滚动条
-          mouseWheelZoom: true, // Ctrl+滚轮调节缩放
-          readOnly: true, // 只读
-          readOnlyMessage: { value: t("ReadOnlyMessage") },
-          padding: {
-            top: 33, // 顶部padding防止遮挡snippets
-          },
-          fontFamily:
-            "Fira Code, Roboto Mono, Source Code Pro, Menlo, Monaco, Consolas, Courier New, monospace",
-        });
+        setRuntimeConfig(data ?? "# Error getting runtime yaml\n");
+        setOpen(true);
       });
     },
     close: () => setOpen(false),
   }));
 
   return (
-    <Dialog open={open} onClose={() => setOpen(false)} maxWidth="xl" fullWidth>
-      <DialogTitle>
-        {t("Runtime Config")} <Chip label={t("ReadOnly")} size="small" />
-      </DialogTitle>
-
-      <DialogContent
-        sx={{ width: "auto", height: "100vh", pb: 1, userSelect: "text" }}
-      >
-        <div style={{ width: "100%", height: "100%" }} ref={editorRef} />
-      </DialogContent>
-
-      <DialogActions>
-        <Button onClick={() => setOpen(false)} variant="outlined">
-          {t("Back")}
-        </Button>
-      </DialogActions>
-    </Dialog>
+    <EditorViewer
+      title={
+        <Box>
+          {t("Runtime Config")}
+          <Chip label={t("ReadOnly")} size="small" />
+        </Box>
+      }
+      mode="text"
+      property={runtimeConfig}
+      open={open}
+      readOnly
+      language="yaml"
+      schema="clash"
+      onClose={() => setOpen(false)}
+    />
   );
 });

+ 1 - 0
src/components/setting/mods/theme-viewer.tsx

@@ -124,6 +124,7 @@ export const ThemeViewer = forwardRef<DialogRef>((props, ref) => {
             {t("Edit")} CSS
           </Button>
           <EditorViewer
+            title={`${t("Edit")} CSS`}
             mode="text"
             property={theme.css_injection ?? ""}
             open={editorOpen}