#!/usr/bin/env bash set -euo pipefail echo "[1/10] Creating Visual Builder..." mkdir -p components/visualbuilder mkdir -p hooks mkdir -p services/builder echo "[2/10] Installing packages..." npm install grapesjs grapesjs-preset-webpage cat > services/builder/client.js <<'EOC' import api from "../api"; export const builder={ load:async(id)=>{ const {data}=await api.get(`/api/builder/${id}`); return data; }, save:async(id,payload)=>{ const {data}=await api.post(`/api/builder/${id}`,payload); return data; }, generate:async(prompt)=>{ const {data}=await api.post("/api/builder/generate",{prompt}); return data; }, export:async(id)=>{ const {data}=await api.get(`/api/builder/${id}/export`); return data; } }; export default builder; EOC cat > hooks/useVisualBuilder.js <<'EOC' "use client"; import {useState} from "react"; import builder from "../services/builder/client"; export default function useVisualBuilder(){ const [loading,setLoading]=useState(false); async function run(fn,...args){ setLoading(true); try{ return await fn(...args); } finally{ setLoading(false); } } return{ loading, load:(...a)=>run(builder.load,...a), save:(...a)=>run(builder.save,...a), generate:(...a)=>run(builder.generate,...a), exportProject:(...a)=>run(builder.export,...a) }; } EOC cat > components/visualbuilder/ProductionVisualBuilder.jsx <<'EOC' "use client"; import {useEffect,useRef} from "react"; import grapesjs from "grapesjs"; import "grapesjs/dist/css/grapes.min.css"; import "grapesjs-preset-webpage"; export default function ProductionVisualBuilder(){ const editorRef=useRef(null); useEffect(()=>{ if(editorRef.current)return; editorRef.current=grapesjs.init({ container:"#gjs", height:"100vh", storageManager:false, plugins:["grapesjs-preset-webpage"], deviceManager:{ devices:[ {name:"Desktop",width:""}, {name:"Tablet",width:"768px"}, {name:"Mobile",width:"375px"} ] } }); return()=>{ editorRef.current?.destroy(); }; },[]); return