Carlen Bai commited on
Commit
185d40b
·
unverified ·
2 Parent(s): b6f5178 7e90cf1

Merge pull request #2 from novitalabs/refine-render

Browse files
Files changed (2) hide show
  1. src/components/preview.tsx +30 -19
  2. src/lib/constants.ts +0 -22
src/components/preview.tsx CHANGED
@@ -1,10 +1,11 @@
1
  "use client"
2
 
3
  import { useState, forwardRef, useImperativeHandle, useEffect, useRef } from "react"
4
- import { DEFAULT_HTML, PARTIAL_GENERATING_HTML_TEMPLATE } from "@/lib/constants"
5
  import { PreviewRef, Version } from "@/lib/types"
6
  import { MinimizeIcon, MaximizeIcon, DownloadIcon } from "./ui/fullscreen-icons"
7
  import { useModel } from "@/lib/contexts/model-context"
 
8
  import { cn } from "@/lib/utils"
9
 
10
  interface PreviewProps {
@@ -27,6 +28,8 @@ export const Preview = forwardRef<PreviewRef, PreviewProps>(function Preview(
27
  const [error, setError] = useState<string | null>(null);
28
  const [showAuthError, setShowAuthError] = useState(false);
29
  const { selectedModelId } = useModel();
 
 
30
 
31
  // Update html when initialHtml changes
32
  useEffect(() => {
@@ -55,26 +58,22 @@ export const Preview = forwardRef<PreviewRef, PreviewProps>(function Preview(
55
  const partialUpdate = (htmlStr: string) => {
56
  const parser = new DOMParser();
57
  const partialDoc = parser.parseFromString(htmlStr, 'text/html');
58
-
59
  const iframe = document.querySelector('iframe');
60
  if (!iframe || !iframe.contentDocument) return;
61
-
62
- // Check if container exists, if not initialize with previewHtml directly
63
- const iframeContainer = iframe.contentDocument.querySelector('#container');
64
- if (!iframeContainer) {
65
- const initDoc = parser.parseFromString(PARTIAL_GENERATING_HTML_TEMPLATE, 'text/html');
66
- if (iframe.contentDocument.documentElement) {
67
- iframe.contentDocument.documentElement.innerHTML = initDoc.documentElement.innerHTML;
68
- }
69
- setHtml(PARTIAL_GENERATING_HTML_TEMPLATE);
70
- return;
71
  }
72
-
73
- // Extract the container content
74
- const containerContent = partialDoc.body?.innerHTML;
75
- if (containerContent && iframeContainer) {
76
- iframeContainer.innerHTML = containerContent;
 
 
77
  }
 
78
  }
79
 
80
  const downloadHtml = () => {
@@ -106,6 +105,8 @@ export const Preview = forwardRef<PreviewRef, PreviewProps>(function Preview(
106
 
107
  const generateCode = async (prompt: string, colors: string[] = [], previousPrompt?: string) => {
108
  setLoading(true);
 
 
109
  if (onLoadingChange) {
110
  onLoadingChange(true);
111
  }
@@ -191,8 +192,8 @@ export const Preview = forwardRef<PreviewRef, PreviewProps>(function Preview(
191
  }, 50);
192
  }
193
  }
194
- break;
195
  setIsPartialGenerating(false);
 
196
  } else {
197
  setIsPartialGenerating(true);
198
  }
@@ -252,7 +253,17 @@ export const Preview = forwardRef<PreviewRef, PreviewProps>(function Preview(
252
 
253
  return (
254
  <div className={`${isFullscreen ? 'fixed inset-0 z-10 bg-novita-dark' : 'h-full'} p-4`}>
255
- <div className="bg-white text-black rounded-md h-full overflow-hidden relative isolation-auto">
 
 
 
 
 
 
 
 
 
 
256
  <div className="absolute top-3 right-3 flex gap-2 z-[100]">
257
  <button
258
  onClick={downloadHtml}
 
1
  "use client"
2
 
3
  import { useState, forwardRef, useImperativeHandle, useEffect, useRef } from "react"
4
+ import { DEFAULT_HTML } from "@/lib/constants"
5
  import { PreviewRef, Version } from "@/lib/types"
6
  import { MinimizeIcon, MaximizeIcon, DownloadIcon } from "./ui/fullscreen-icons"
7
  import { useModel } from "@/lib/contexts/model-context"
8
+ import { Loader2 } from "lucide-react"
9
  import { cn } from "@/lib/utils"
10
 
11
  interface PreviewProps {
 
28
  const [error, setError] = useState<string | null>(null);
29
  const [showAuthError, setShowAuthError] = useState(false);
30
  const { selectedModelId } = useModel();
31
+ const renderCount = useRef(0);
32
+ const headUpdated = useRef(false);
33
 
34
  // Update html when initialHtml changes
35
  useEffect(() => {
 
58
  const partialUpdate = (htmlStr: string) => {
59
  const parser = new DOMParser();
60
  const partialDoc = parser.parseFromString(htmlStr, 'text/html');
 
61
  const iframe = document.querySelector('iframe');
62
  if (!iframe || !iframe.contentDocument) return;
63
+
64
+ const iframeContainer = iframe.contentDocument;
65
+ if (iframeContainer?.body && iframeContainer) {
66
+ iframeContainer.body.innerHTML = partialDoc.body?.innerHTML;
 
 
 
 
 
 
67
  }
68
+ if (renderCount.current % 10 === 0 && !headUpdated.current) {
69
+ setHtml(htmlStr);
70
+ if (htmlStr.includes('</head>')) {
71
+ setTimeout(() => {
72
+ headUpdated.current = true;
73
+ }, 1000);
74
+ }
75
  }
76
+ renderCount.current++;
77
  }
78
 
79
  const downloadHtml = () => {
 
105
 
106
  const generateCode = async (prompt: string, colors: string[] = [], previousPrompt?: string) => {
107
  setLoading(true);
108
+ renderCount.current = 0;
109
+ headUpdated.current = false;
110
  if (onLoadingChange) {
111
  onLoadingChange(true);
112
  }
 
192
  }, 50);
193
  }
194
  }
 
195
  setIsPartialGenerating(false);
196
+ break;
197
  } else {
198
  setIsPartialGenerating(true);
199
  }
 
253
 
254
  return (
255
  <div className={`${isFullscreen ? 'fixed inset-0 z-10 bg-novita-dark' : 'h-full'} p-4`}>
256
+ { isPartialGenerating && (
257
+ <div className="w-full bg-slate-50 border-b border-slate-200 py-2 px-4">
258
+ <div className="container mx-auto flex items-center justify-center">
259
+ <div className="flex items-center space-x-2 text-slate-700">
260
+ <Loader2 className="h-4 w-4 animate-spin" />
261
+ <span className="text-sm font-medium">building...</span>
262
+ </div>
263
+ </div>
264
+ </div>
265
+ )}
266
+ <div className="bg-white text-black h-full overflow-hidden relative isolation-auto">
267
  <div className="absolute top-3 right-3 flex gap-2 z-[100]">
268
  <button
269
  onClick={downloadHtml}
src/lib/constants.ts CHANGED
@@ -88,25 +88,3 @@ export const DEFAULT_HTML = `<!DOCTYPE html>
88
  </div>
89
  </body>
90
  </html>`;
91
-
92
- export const PARTIAL_GENERATING_HTML_TEMPLATE = `
93
- <!DOCTYPE html>
94
- <html lang="en">
95
- <head>
96
- <meta charset="UTF-8">
97
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
98
- <title>Novita AnySite</title>
99
- <script src="https://cdn.tailwindcss.com"></script>
100
- </head>
101
- <body>
102
- <div id="container" class="py-10">
103
- </div>
104
- <div class="fixed inset-0 bg-gray-300 bg-opacity-25 flex items-center justify-center z-50">
105
- <div class="flex flex-col items-center">
106
- <div class="animate-spin rounded-full h-8 w-8 border-b-2 border-gray-600"></div>
107
- <p class="mt-3 text-gray-600 text-sm">Loading...</p>
108
- </div>
109
- </div>
110
- </body>
111
- </html>
112
- `;
 
88
  </div>
89
  </body>
90
  </html>`;