diff --git a/apps/client/src/features/app-settings/panel/settings-panel/composite/StyleEditor.module.scss b/apps/client/src/features/app-settings/panel/settings-panel/composite/StyleEditor.module.scss
index 891dda43b..29c11e012 100644
--- a/apps/client/src/features/app-settings/panel/settings-panel/composite/StyleEditor.module.scss
+++ b/apps/client/src/features/app-settings/panel/settings-panel/composite/StyleEditor.module.scss
@@ -1,4 +1,5 @@
.wrapper {
+ min-height: 500px;
max-height: 500px;
overflow-y: auto;
}
diff --git a/apps/client/src/features/app-settings/panel/settings-panel/composite/StyleEditor.tsx b/apps/client/src/features/app-settings/panel/settings-panel/composite/StyleEditor.tsx
index c9639a0db..a175ca43e 100644
--- a/apps/client/src/features/app-settings/panel/settings-panel/composite/StyleEditor.tsx
+++ b/apps/client/src/features/app-settings/panel/settings-panel/composite/StyleEditor.tsx
@@ -1,71 +1,38 @@
import Prism from 'virtual:prismjs';
-import { forwardRef, memo, useEffect, useImperativeHandle, useState } from 'react';
+import { memo } from 'react';
import Editor from 'react-simple-code-editor';
import 'prismjs/components/prism-css';
import 'prismjs/themes/prism-tomorrow.min.css';
+
import style from './StyleEditor.module.scss';
interface CodeEditorProps {
language: string;
- initialValue: string;
- isDirty: boolean;
- setIsDirty: (value: boolean) => void;
+ value: string;
+ onChange: (value: string) => void;
}
-const CodeEditor = forwardRef((props: CodeEditorProps, cssRef) => {
- const { language, initialValue, isDirty, setIsDirty } = props;
-
- const [code, setCode] = useState(initialValue);
-
+export default memo(CodeEditor);
+function CodeEditor({ language, onChange, value }: CodeEditorProps) {
const highlight = (code: string) => {
const grammar = Prism.languages[language];
return grammar ? Prism.highlight(code, grammar, language) : code;
};
- const handleChange = (newCode: string) => {
- setCode(newCode);
- };
-
- useImperativeHandle(cssRef, () => {
- return {
- getCss: () => code,
- };
- });
-
- // add contents to editor on mount and any change in initialValue
- useEffect(() => {
- setCode(initialValue);
- }, [initialValue]);
-
- // handle dirty state on change
- useEffect(() => {
- if (initialValue.trim() !== code.trim() && !isDirty && code.length !== 0) {
- setIsDirty(true);
- }
-
- if (initialValue.trim() === code.trim() && isDirty) {
- setIsDirty(false);
- }
- }, [initialValue, code, isDirty, setIsDirty]);
-
return (
);
-});
-
-CodeEditor.displayName = 'StyleEditor';
-
-export default memo(CodeEditor);
+}
diff --git a/apps/client/src/features/app-settings/panel/settings-panel/composite/StyleEditorModal.module.scss b/apps/client/src/features/app-settings/panel/settings-panel/composite/StyleEditorModal.module.scss
index 084608cc4..4418f2a34 100644
--- a/apps/client/src/features/app-settings/panel/settings-panel/composite/StyleEditorModal.module.scss
+++ b/apps/client/src/features/app-settings/panel/settings-panel/composite/StyleEditorModal.module.scss
@@ -13,3 +13,12 @@
gap: 1rem;
flex-direction: column;
}
+
+.editorBody {
+ position: relative;
+ min-height: 500px;
+ background-color: $gray-1350;
+ border: 1px solid $gray-1100;
+ border-radius: 3px;
+ overflow: hidden;
+}
diff --git a/apps/client/src/features/app-settings/panel/settings-panel/composite/StyleEditorModal.tsx b/apps/client/src/features/app-settings/panel/settings-panel/composite/StyleEditorModal.tsx
index c91c5c20b..58023911f 100644
--- a/apps/client/src/features/app-settings/panel/settings-panel/composite/StyleEditorModal.tsx
+++ b/apps/client/src/features/app-settings/panel/settings-panel/composite/StyleEditorModal.tsx
@@ -1,4 +1,4 @@
-import { Suspense, lazy, useEffect, useRef, useState } from 'react';
+import { Suspense, lazy, useEffect, useState } from 'react';
import { getCSSContents, postCSSContents, restoreCSSContents } from '../../../../../common/api/assets';
import Button from '../../../../../common/components/buttons/Button';
@@ -15,24 +15,21 @@ interface CodeEditorModalProps {
onClose: () => void;
}
-interface CSSRef {
- getCss: () => string;
-}
-
export default function CodeEditorModal({ isOpen, onClose }: CodeEditorModalProps) {
- const [css, setCSS] = useState('');
- const [isDirty, setIsDirty] = useState(false);
+ const [savedCss, setSavedCss] = useState('');
+ const [draftCss, setDraftCss] = useState('');
+ const [isLoadingCss, setIsLoadingCss] = useState(false);
const [saveLoading, setSaveLoading] = useState(false);
const [resetLoading, setResetLoading] = useState(false);
const [error, setError] = useState(null);
- const cssRef = useRef(null);
+ const isDirty = savedCss.trim() !== draftCss.trim();
const handleRestore = async () => {
try {
setResetLoading(true);
const defaultCss = await restoreCSSContents();
- setCSS(defaultCss);
+ setDraftCss(defaultCss);
} catch (_error) {
/** no error handling for now */
} finally {
@@ -43,11 +40,8 @@ export default function CodeEditorModal({ isOpen, onClose }: CodeEditorModalProp
const handleSave = async () => {
try {
setSaveLoading(true);
- if (cssRef.current) {
- await postCSSContents(cssRef.current.getCss());
- setCSS(cssRef.current.getCss());
- setIsDirty(false);
- }
+ await postCSSContents(draftCss);
+ setSavedCss(draftCss);
} catch (_error) {
/** no error handling for now */
} finally {
@@ -55,22 +49,43 @@ export default function CodeEditorModal({ isOpen, onClose }: CodeEditorModalProp
}
};
- const clear = () => setCSS('');
+ const clear = () => setDraftCss('');
useEffect(() => {
+ let isCancelled = false;
+
async function fetchServerCSS() {
// check for isOpen to fetch recent css
if (isOpen) {
try {
+ setError(null);
+ setIsLoadingCss(true);
const css = await getCSSContents();
- setCSS(css);
+ if (isCancelled) {
+ return;
+ }
+ setSavedCss(css);
+ setDraftCss(css);
} catch (_error) {
+ if (isCancelled) {
+ return;
+ }
+ setSavedCss('');
+ setDraftCss('');
setError('Failed to load CSS from server');
/** no error handling for now */
+ } finally {
+ if (!isCancelled) {
+ setIsLoadingCss(false);
+ }
}
}
}
fetchServerCSS();
+
+ return () => {
+ isCancelled = true;
+ };
}, [isOpen]);
return (
@@ -81,9 +96,14 @@ export default function CodeEditorModal({ isOpen, onClose }: CodeEditorModalProp
showCloseButton
showBackdrop
bodyElements={
-
-
-
+
+ {!isLoadingCss && (
+
}>
+
+
+ )}
+
+
}
footerElements={