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 (