file-editor.tsx 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import useSWR from "swr";
  2. import { useEffect, useRef } from "react";
  3. import { useLockFn } from "ahooks";
  4. import { useTranslation } from "react-i18next";
  5. import {
  6. Button,
  7. Dialog,
  8. DialogActions,
  9. DialogContent,
  10. DialogTitle,
  11. } from "@mui/material";
  12. import {
  13. getVergeConfig,
  14. readProfileFile,
  15. saveProfileFile,
  16. } from "../../services/cmds";
  17. import Notice from "../base/base-notice";
  18. import "monaco-editor/esm/vs/basic-languages/javascript/javascript.contribution.js";
  19. import "monaco-editor/esm/vs/basic-languages/yaml/yaml.contribution.js";
  20. import "monaco-editor/esm/vs/editor/contrib/folding/browser/folding.js";
  21. import { editor } from "monaco-editor/esm/vs/editor/editor.api";
  22. interface Props {
  23. uid: string;
  24. open: boolean;
  25. mode: "yaml" | "javascript";
  26. onClose: () => void;
  27. onChange?: () => void;
  28. }
  29. const FileEditor = (props: Props) => {
  30. const { uid, open, mode, onClose, onChange } = props;
  31. const { t } = useTranslation();
  32. const editorRef = useRef<any>();
  33. const instanceRef = useRef<editor.IStandaloneCodeEditor | null>(null);
  34. const { data: vergeConfig } = useSWR("getVergeConfig", getVergeConfig);
  35. const { theme_mode } = vergeConfig ?? {};
  36. useEffect(() => {
  37. if (!open) return;
  38. readProfileFile(uid).then((data) => {
  39. const dom = editorRef.current;
  40. if (!dom) return;
  41. if (instanceRef.current) instanceRef.current.dispose();
  42. instanceRef.current = editor.create(editorRef.current, {
  43. value: data,
  44. language: mode,
  45. theme: theme_mode === "light" ? "vs" : "vs-dark",
  46. minimap: { enabled: false },
  47. });
  48. });
  49. return () => {
  50. if (instanceRef.current) {
  51. instanceRef.current.dispose();
  52. instanceRef.current = null;
  53. }
  54. };
  55. }, [open]);
  56. const onSave = useLockFn(async () => {
  57. const value = instanceRef.current?.getValue();
  58. if (value == null) return;
  59. try {
  60. await saveProfileFile(uid, value);
  61. onChange?.();
  62. } catch (err: any) {
  63. Notice.error(err.message || err.toString());
  64. }
  65. });
  66. return (
  67. <Dialog open={open} onClose={onClose}>
  68. <DialogTitle>{t("Edit File")}</DialogTitle>
  69. <DialogContent sx={{ width: 520, pb: 1 }}>
  70. <div style={{ width: "100%", height: "420px" }} ref={editorRef} />
  71. </DialogContent>
  72. <DialogActions>
  73. <Button onClick={onClose}>{t("Cancel")}</Button>
  74. <Button onClick={onSave} variant="contained">
  75. {t("Save")}
  76. </Button>
  77. </DialogActions>
  78. </Dialog>
  79. );
  80. };
  81. export default FileEditor;