File size: 2,384 Bytes
c2c8c8d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import { useMemo } from 'react';
import { useFileStore } from '@/stores/fileStore';
import { useEditorStore } from '@/stores/editorStore';

export function useLivePreview() {
  const baseFiles = useFileStore((s) => s.files);
  const openFiles = useEditorStore((s) => s.openFiles);

  // Merge: start with file store, then overlay any open editor buffers
  const files = useMemo(() => {
    const merged = { ...baseFiles };
    for (const [path, file] of Object.entries(openFiles)) {
      merged[path] = typeof file === 'string' ? file : file.content;
    }
    return merged;
  }, [baseFiles, openFiles]);

  const srcdoc = useMemo(() => {
    const htmlFile = files['index.html'] || Object.entries(files).find(([k]) => k.endsWith('.html'))?.[1];
    if (!htmlFile) return '<html><body style="background:#0a0a0f;color:#888;display:flex;align-items:center;justify-content:center;height:100vh;font-family:sans-serif"><p>No HTML file found. Create an index.html to see a preview.</p></body></html>';

    let html = htmlFile;

    // Inline CSS
    const cssLinkRegex = /<link[^>]+href=["']([^"']+\.css)["'][^>]*>/gi;
    html = html.replace(cssLinkRegex, (_match, href) => {
      const cssContent = files[href];
      return cssContent ? `<style>${cssContent}</style>` : '';
    });

    // Inline JS
    const scriptRegex = /<script[^>]+src=["']([^"']+\.js)["'][^>]*><\/script>/gi;
    html = html.replace(scriptRegex, (_match, src) => {
      const jsContent = files[src];
      return jsContent ? `<script>${jsContent}<\/script>` : '';
    });

    // Add console bridge
    const consoleBridge = `<script>
      const _origConsole = { log: console.log, warn: console.warn, error: console.error };
      ['log', 'warn', 'error'].forEach(method => {
        console[method] = function(...args) {
          _origConsole[method].apply(console, args);
          try {
            window.parent.postMessage({ type: 'console', method, args: args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a)) }, '*');
          } catch(e) {}
        };
      });
      window.onerror = function(msg, src, line, col, err) {
        window.parent.postMessage({ type: 'console', method: 'error', args: [msg + ' (line ' + line + ')'] }, '*');
      };
    <\/script>`;

    html = html.replace('</head>', `${consoleBridge}</head>`);

    return html;
  }, [files]);

  return { srcdoc };
}