diff --git a/frontend/package.json b/frontend/package.json index 7a34ab2..78ce51e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -22,6 +22,7 @@ "classnames": "^2.3.2", "clsx": "^2.0.0", "codemirror": "^6.0.1", + "html2canvas": "^1.4.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-dropzone": "^14.2.3", diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 6bb0c80..d533d89 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -12,6 +12,7 @@ import { FaMobile, FaUndo, } from "react-icons/fa"; +import { Switch } from "./components/ui/switch"; import { Button } from "@/components/ui/button"; import { Textarea } from "@/components/ui/textarea"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "./components/ui/tabs"; @@ -24,6 +25,8 @@ import { OnboardingNote } from "./components/OnboardingNote"; import { usePersistedState } from "./hooks/usePersistedState"; import { UrlInputSection } from "./components/UrlInputSection"; import TermsOfServiceDialog from "./components/TermsOfServiceDialog"; +import html2canvas from 'html2canvas'; + function App() { const [appState, setAppState] = useState( @@ -43,8 +46,20 @@ function App() { }, "setting" ); + const [isImgCompare, setIsImgCompare] = useState(false); const wsRef = useRef(null); + const takeScreenshot = async (): Promise => { + const iframeElement = document.querySelector('#preview-desktop') as HTMLIFrameElement; + if (!iframeElement?.contentWindow?.document.body) { + return ''; + } + + const canvas = await html2canvas(iframeElement.contentWindow.document.body); + const png = canvas.toDataURL('image/png'); + return png; + } + const downloadCode = () => { // Create a blob from the generated code const blob = new Blob([generatedCode], { type: "text/html" }); @@ -72,6 +87,8 @@ function App() { const stop = () => { wsRef.current?.close?.(USER_CLOSE_WEB_SOCKET_CODE); + // make sure stop can correct the state even if the websocket is already closed + setAppState(AppStatus.CODE_READY); } function doGenerateCode(params: CodeGenerationParams) { @@ -103,14 +120,24 @@ function App() { } // Subsequent updates - function doUpdate() { + async function doUpdate() { const updatedHistory = [...history, generatedCode, updateInstruction]; - - doGenerateCode({ - generationType: "update", - image: referenceImages[0], - history: updatedHistory, - }); + let resultImg = referenceImages[0]; + if (isImgCompare) { + resultImg = await takeScreenshot(); + doGenerateCode({ + generationType: "update", + image: referenceImages[0], + resultImg: resultImg, + history: updatedHistory, + }); + } else { + doGenerateCode({ + generationType: "update", + image: referenceImages[0], + history: updatedHistory, + }); + } setHistory(updatedHistory); setGeneratedCode(""); @@ -160,6 +187,15 @@ function App() { {appState === AppStatus.CODE_READY && (
+
+
+ Auto Image Comparison +
+ +