file-editor.tsx 2.5 KB

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