diff --git a/README.md b/README.md
index 81cc82a..a6dfabc 100644
--- a/README.md
+++ b/README.md
@@ -12,8 +12,9 @@ See the [Examples](#examples) section below for more demos.
## 🌟 Recent Updates
+- Nov 21 - You can now edit code in the code editor and preview changes live thanks to [@clean99](https://github.com/clean99)
- Nov 20 - Paste in a URL to screenshot and clone (requires [ScreenshotOne free API key](https://screenshotone.com?via=screenshot-to-code))
-- Nov 19 - Support for dark/light code editor theme - thanks https://github.com/kachbit
+- Nov 19 - Support for dark/light code editor theme - thanks [@kachbit](https://github.com/kachbit)
- Nov 16 - Added a setting to disable DALL-E image generation if you don't need that
- Nov 16 - View code directly within the app
- Nov 15 - 🔥 You can now instruct the AI to update the code as you wish. It is helpful if the AI messed up some styles or missed a section.
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 50bb48a..4bb0728 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -22,7 +22,7 @@ import { Textarea } from "@/components/ui/textarea";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "./components/ui/tabs";
import CodeMirror from "./components/CodeMirror";
import SettingsDialog from "./components/SettingsDialog";
-import { AppStatus, Settings } from "@/types";
+import { Settings, EditorTheme, AppState } from "./types";
import { IS_RUNNING_ON_CLOUD } from "./config";
import { PicoBadge } from "./components/PicoBadge";
import { OnboardingNote } from "./components/OnboardingNote";
@@ -44,7 +44,8 @@ function App() {
openAiApiKey: null,
screenshotOneApiKey: null,
isImageGenerationEnabled: true,
- editorTheme: "cobalt",
+ editorTheme: EditorTheme.COBALT,
+ isTermOfServiceAccepted: false,
},
"setting"
);
@@ -150,10 +151,22 @@ function App() {
toast.success("Copied to clipboard");
}, [generatedCode]);
+ const handleTermDialogOpenChange = (open: boolean) => {
+ setSettings((s) => ({
+ ...s,
+ isTermOfServiceAccepted: !open,
+ }));
+ };
+
return (
{IS_RUNNING_ON_CLOUD &&
}
- {IS_RUNNING_ON_CLOUD &&
}
+ {IS_RUNNING_ON_CLOUD && (
+
+ )}
@@ -301,6 +314,7 @@ function App() {
void;
}
-function CodeMirror({ code, editorTheme }: Props) {
+function CodeMirror({ code, editorTheme, onCodeChange }: Props) {
const ref = useRef(null);
const view = useRef(null);
-
- useEffect(() => {
- let selectedTheme = cobalt;
- if (editorTheme === "espresso") {
- selectedTheme = espresso;
- }
- view.current = new EditorView({
- state: EditorState.create({
- doc: code,
- extensions: [
- history(),
- keymap.of([
- ...defaultKeymap,
- indentWithTab,
- { key: "Mod-z", run: undo, preventDefault: true },
- { key: "Mod-Shift-z", run: redo, preventDefault: true },
- ]),
- lineNumbers(),
- bracketMatching(),
- html(),
- selectedTheme,
- EditorView.lineWrapping,
- ],
+ const editorState = useMemo(() => EditorState.create({
+ extensions: [
+ history(),
+ keymap.of([
+ ...defaultKeymap,
+ indentWithTab,
+ { key: "Mod-z", run: undo, preventDefault: true },
+ { key: "Mod-Shift-z", run: redo, preventDefault: true },
+ ]),
+ lineNumbers(),
+ bracketMatching(),
+ html(),
+ editorTheme === EditorTheme.ESPRESSO ? espresso : cobalt,
+ EditorView.lineWrapping,
+ EditorView.updateListener.of((update: ViewUpdate) => {
+ if (update.docChanged) {
+ const updatedCode = update.state.doc.toString();
+ onCodeChange(updatedCode);
+ }
}),
+ ],
+ }), [editorTheme]);
+ useEffect(() => {
+ view.current = new EditorView({
+ state: editorState,
parent: ref.current as Element,
});
@@ -53,7 +56,7 @@ function CodeMirror({ code, editorTheme }: Props) {
view.current = null;
}
};
- }, [code, editorTheme]);
+ }, []);
useEffect(() => {
if (view.current && view.current.state.doc.toString() !== code) {
@@ -69,3 +72,4 @@ function CodeMirror({ code, editorTheme }: Props) {
}
export default CodeMirror;
+
diff --git a/frontend/src/components/Preview.tsx b/frontend/src/components/Preview.tsx
index 497bfa9..24f33c0 100644
--- a/frontend/src/components/Preview.tsx
+++ b/frontend/src/components/Preview.tsx
@@ -1,3 +1,4 @@
+import { useEffect, useRef } from 'react';
import classNames from "classnames";
import useThrottle from "../hooks/useThrottle";
@@ -8,13 +9,23 @@ interface Props {
function Preview({ code, device }: Props) {
const throttledCode = useThrottle(code, 200);
+ const iframeRef = useRef(null);
+
+ useEffect(() => {
+ const iframe = iframeRef.current;
+ if (iframe && iframe.contentDocument) {
+ iframe.contentDocument.open();
+ iframe.contentDocument.write(throttledCode);
+ iframe.contentDocument.close();
+ }
+ }, [throttledCode]);
return (