253 lines
7.7 KiB
TypeScript
253 lines
7.7 KiB
TypeScript
import { useEffect, useState, useContext } from 'react';
|
|
import { DesignerView, Designer, AutoCodePluginManager, ILowCodePluginContext } from './designer';
|
|
import { Editor, globalContext } from './editor-core';
|
|
import { AppState, GeneratedCodeConfig } from "../components/types";
|
|
import html2canvas from "html2canvas";
|
|
import {HistoryContext} from '../components/contexts/HistoryContext';
|
|
import {EditorContext, deviceType} from '../components/contexts/EditorContext';
|
|
import { cloneDeep } from 'lodash';
|
|
import {
|
|
FaBug
|
|
} from "react-icons/fa";
|
|
import filesTemplate from './apps/react-shadcnui/files-template';
|
|
import { useSandpack, SandpackProvider } from "@codesandbox/sandpack-react";
|
|
import { cn } from "../components/lib/utils"
|
|
import classNames from "classnames";
|
|
|
|
// filesTemplate['/src/Preview.jsx'] = `
|
|
// import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "components/ui/card";
|
|
// import { Button } from "components/ui/button";
|
|
|
|
// export default function App() {
|
|
// return (
|
|
// <div className="p-8">
|
|
// loading
|
|
// </div>
|
|
// );
|
|
// }
|
|
// `;
|
|
|
|
interface ISandpackProps {
|
|
sandpackDone: () => void;
|
|
}
|
|
|
|
const SandpackCustom = ({
|
|
sandpackDone
|
|
}: ISandpackProps) => {
|
|
const { dispatch, listen, sandpack } = useSandpack();
|
|
|
|
useEffect(() => {
|
|
// listens for any message dispatched between sandpack and the bundler
|
|
const stopListening = listen((msg) => {
|
|
console.log('msg',msg)
|
|
if (msg.type === 'done') {
|
|
setTimeout(() => {
|
|
sandpackDone();
|
|
}, 500);
|
|
}
|
|
});
|
|
|
|
return () => {
|
|
// unsubscribe
|
|
stopListening();
|
|
};
|
|
}, [listen]);
|
|
|
|
return (
|
|
<></>
|
|
);
|
|
};
|
|
|
|
const editor = new Editor();
|
|
globalContext.register(editor, Editor);
|
|
globalContext.register(editor, 'editor');
|
|
|
|
const designer = new Designer({ editor });
|
|
editor.set('designer' as any, designer);
|
|
const plugins = new AutoCodePluginManager(editor).toProxy();
|
|
(async function registerPlugins() {
|
|
const editorInit = (ctx: ILowCodePluginContext) => {
|
|
return {
|
|
name: 'editor-init',
|
|
async init() {
|
|
// 设置物料描述
|
|
const { project } = ctx;
|
|
|
|
// 加载 schema
|
|
project.open();
|
|
},
|
|
};
|
|
};
|
|
editorInit.pluginName = 'editorInit';
|
|
await plugins.register(editorInit);
|
|
// pluginPreference
|
|
await plugins.init({} as any);
|
|
|
|
})();
|
|
|
|
interface Props {
|
|
code: string;
|
|
appState: AppState;
|
|
sendMessageChange: (e: any) => void;
|
|
history: any;
|
|
generatedCodeConfig: GeneratedCodeConfig,
|
|
fixBug: (error: {
|
|
message: string;
|
|
stack: string;
|
|
}) => void;
|
|
}
|
|
|
|
export default function PreviewBox({ code, appState, sendMessageChange, history, generatedCodeConfig, fixBug }: Props) {
|
|
const {updateHistoryScreenshot} = useContext(HistoryContext);
|
|
const [showDebug, setShowDebug] = useState<boolean>(false);
|
|
const [errorObj, setErrorObj] = useState({
|
|
message: '',
|
|
stack: ''
|
|
});
|
|
const [initSandpack, setInitSandpack] = useState<boolean>(false);
|
|
// const { dispatch, listen } = useSandpack();
|
|
|
|
|
|
const { enableEdit, setEnableEdit, device } = useContext(EditorContext);
|
|
const [filesObj, setFilesObj]= useState<any>(filesTemplate);
|
|
|
|
|
|
useEffect(() => {
|
|
if (enableEdit) {
|
|
designer.project.simulator?.set('designMode', 'design')
|
|
} else {
|
|
designer.project.simulator?.set('designMode', 'live')
|
|
}
|
|
}, [enableEdit])
|
|
|
|
const onIframeLoad = async () => {
|
|
const img = await takeScreenshot();
|
|
setTimeout(() => {
|
|
updateHistoryScreenshot(img);
|
|
}, 1000)
|
|
}
|
|
|
|
useEffect(() => {
|
|
editor.on('editor.sendMessageChange', sendMessageChange);
|
|
document.querySelector('.lc-simulator-content-frame')?.addEventListener('load', onIframeLoad);
|
|
// document.querySelector('.sp-preview-iframe')?.addEventListener('load', onIframeLoad);
|
|
return () => {
|
|
editor.removeListener('editor.sendMessageChange', sendMessageChange);
|
|
document.querySelector('.lc-simulator-content-frame')?.removeEventListener('load', onIframeLoad);
|
|
// document.querySelector('.sp-preview-iframe')?.removeEventListener('load', onIframeLoad);
|
|
}
|
|
}, [history]);
|
|
|
|
|
|
useEffect(() => {
|
|
if (appState === AppState.CODE_READY) {
|
|
designer.project.simulator?.writeIframeDocument(code);
|
|
} else if(appState === AppState.INITIAL) {
|
|
filesTemplate['/src/Preview.jsx'] = `
|
|
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "components/ui/card";
|
|
import { Button } from "components/ui/button";
|
|
|
|
export default function App() {
|
|
return (
|
|
<div className="p-8">
|
|
loading
|
|
</div>
|
|
);
|
|
}
|
|
`;
|
|
setFilesObj((prev: any) => {
|
|
const newFiles = {...prev};
|
|
newFiles['/src/Preview.jsx'] = filesTemplate['/src/Preview.jsx'];
|
|
return newFiles;
|
|
});
|
|
}
|
|
}, [code, appState]);
|
|
|
|
useEffect(() => {
|
|
const messageHandler = (e: any) => {
|
|
if (e.data && e.data.error) {
|
|
setErrorObj({
|
|
message: e.data.error.message,
|
|
stack: e.data.error.stack
|
|
});
|
|
setShowDebug(true);
|
|
}
|
|
}
|
|
window.addEventListener('message', messageHandler);
|
|
return () => {
|
|
window.removeEventListener('message', messageHandler);
|
|
}
|
|
}, [])
|
|
|
|
const takeScreenshot = async (): Promise<string> => {
|
|
const body = designer.project.simulator?.contentWindow?.document.body;
|
|
if (!body) {
|
|
return "";
|
|
} else {
|
|
const canvas = await html2canvas(body);
|
|
const png = canvas.toDataURL("image/png");
|
|
return png;
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div
|
|
className="border-[4px] border-black rounded-[10px] shadow-lg h-full w-full"
|
|
>
|
|
{
|
|
showDebug && (
|
|
<span
|
|
onClick={() => {
|
|
fixBug(errorObj);
|
|
}}
|
|
className='text-red-600 absolute right-14 top-16 z-[50] hover:bg-slate-200 rounded-sm p-2'>
|
|
<FaBug />
|
|
</span>
|
|
)
|
|
}
|
|
{
|
|
initSandpack &&
|
|
(
|
|
<SandpackProvider
|
|
template="react"
|
|
options={{
|
|
bundlerURL: `${location.origin}/sandpack/`,
|
|
classes: {
|
|
"sp-wrapper": "ant-codeai-wrapper",
|
|
}
|
|
}}
|
|
// @ts-ignore
|
|
files={filesObj}
|
|
>
|
|
<SandpackCustom sandpackDone={async () => {
|
|
const img = await takeScreenshot();
|
|
setTimeout(() => {
|
|
updateHistoryScreenshot(img);
|
|
}, 1000)
|
|
}}/>
|
|
<DesignerView
|
|
editor={editor}
|
|
designer={editor.get('designer')}
|
|
simulatorProps={{
|
|
simulatorUrl: '',
|
|
isSandpack: true,
|
|
files: filesObj,
|
|
}}
|
|
/>
|
|
</SandpackProvider>
|
|
)
|
|
}
|
|
{
|
|
<DesignerView
|
|
editor={editor}
|
|
designer={editor.get('designer')}
|
|
simulatorProps={{
|
|
simulatorUrl: '',
|
|
isSandpack: false,
|
|
files: filesObj,
|
|
}}
|
|
/>
|
|
}
|
|
</div>
|
|
)
|
|
} |