import React, { useEffect, useMemo, useRef, useState } from "react"; import { Editor } from "@monaco-editor/react"; import { motion } from "framer-motion"; import { Download, Wand2, GitBranch, Eye, Layers, Loader2, Bug } from "lucide-react"; import JSZip from "jszip"; // NOTE: Use default import for file-saver to avoid ESM named-export errors in some bundlers/CDNs import saveAs from "file-saver"; // --- shadcn/ui --- import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"; import { Textarea } from "@/components/ui/textarea"; import { Switch } from "@/components/ui/switch"; import { Label } from "@/components/ui/label"; // --- Minimal in-browser sandbox that behaves like a tiny Lovable preview --- // We keep a virtual FS with three files and render them into an iframe using a Blob URL. const DEFAULT_HTML = `
Edit index.html, style.css, or script.js and see changes live.
", ``); return withJs; } function useBlobPreview({ html, css, js }) { const urlRef = useRef(null); const srcDoc = useMemo(() => composeHtml(html, css, js), [html, css, js]); useEffect(() => { if (urlRef.current) URL.revokeObjectURL(urlRef.current); const blob = new Blob([srcDoc], { type: 'text/html' }); const url = URL.createObjectURL(blob); urlRef.current = url; return () => { if (urlRef.current) URL.revokeObjectURL(urlRef.current); }; }, [srcDoc]); return urlRef.current; } // --- Heuristic AI scaffolder (offline) --- // In production, replace with your AI API call; for now we synthesize boilerplates deterministically from the prompt. async function mockGenerateFromPrompt(prompt) { await new Promise(r => setTimeout(r, 700)); const p = prompt.toLowerCase(); const wantsAuth = /auth|login|signup|sign up|account/.test(p); const wantsTodo = /todo|task|kanban|list/.test(p); const wantsChat = /chat|message|support|assistant/.test(p); const html = `