skilld-frontend/src/components/task/editor-window.tsx

228 lines
7.2 KiB
TypeScript

"use client";
import React, { useEffect, useState } from "react";
import { compileCode } from "./compiler";
import { v4 as uuid } from "uuid";
import { CodeEditor } from "./code-editor";
import { ErrorBoundary } from "react-error-boundary";
import PreviewErrorFallback from "./preview-error-fallback";
import {
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
} from "@/components/ui/resizable";
import { ThemeDropdown } from "./theme-dropdown";
import LanguagesDropdown from "./languages-dropdown";
import Output from "./output";
import { tutorialData } from "@/constants/tutorial-data";
import { notFound, useRouter } from "next/navigation";
import { defineTheme } from "@/utils/define-theme";
import Preview from "./preview";
import { MyComponents } from "./my-components";
import { cn } from "@/lib/utils";
export default function EditorWindow({
activeMobileView: activeMobileView,
language: lang,
step,
}: {
activeMobileView: "tutorial" | "code" | "output";
language: string;
step: number;
}) {
const [componentName, setComponentName] = useState<any>("");
const [theme, setTheme] = useState("cobalt");
// const [language, setLanguage] = useState(languageOptions[0]);
// const [language, setLanguage] = useState("react");
// const [defaultCode, setDefaultCode] = useState("");
const [codeValue, setCodeValue] = useState("");
const router = useRouter();
const handleCodeChange = (code: string | undefined) => {
try {
setCodeValue(code || "");
const func = compileCode(code || "");
const id = uuid();
MyComponents[id] = func(React);
setComponentName(id);
} catch (err) {
console.log(err);
// setComponentName("error");
}
};
useEffect(() => {
defineTheme("cobalt").then((_) => setTheme("cobalt"));
}, []);
function handleThemeChange(th: string) {
const themee = th;
// console.log("theme...", theme);
if (["light", "vs-dark"].includes(themee)) {
setTheme(themee);
} else {
defineTheme(themee).then((_) => setTheme(themee));
}
}
const handleLanguageChange = (lang: string) => {
router.push(`/dashboard/task/${lang}/1`);
// try {
// if (lang === "react") {
// const func = compileCode(CODE_SNIPPETS[lang]);
// const id = uuid();
// MyComponents[id] = func(React);
// setComponentName(id);
// }
// setLanguage(lang);
// // @ts-ignore
// setCodeValue(CODE_SNIPPETS[lang]);
// // @ts-ignore
// // setDefaultCode(CODE_SNIPPETS[language]);
// } catch (error) {
// // console.log(error);
// }
};
const tutorial = tutorialData
.find((t) => t.language === lang)
?.tutorial.find((t) => t.id === step);
if (!tutorial) {
notFound();
}
// console.log(tutorial);
return (
<>
<div className="md:hidden">
{/* <ResizablePanelGroup direction="vertical" className="border-r">
<ResizablePanel defaultSize={50}> */}
<div
className={cn(
"fixed left-0 top-0 h-[calc(100vh-59px)] w-screen translate-x-full transition-transform ",
activeMobileView === "tutorial"
? "translate-x-full"
: activeMobileView === "code"
? "translate-x-0"
: activeMobileView === "output"
? "-translate-x-full"
: "",
)}
>
<div className="p-2 flex gap-4">
<ThemeDropdown
handleThemeChange={handleThemeChange}
theme={theme}
/>
{/* <LanguagesDropdown
handleLanguageChange={handleLanguageChange}
language={lang}
/> */}
</div>
<div className="h-[calc(100vh-calc(57px+53px))]">
<CodeEditor
codeValue={codeValue}
// @ts-ignore
// defaultCode={CODE_SNIPPETS[language]}
defaultCode={tutorial?.code || ""}
onChange={handleCodeChange}
theme={theme}
// language={language}
language={lang}
/>
</div>
</div>
{/* </ResizablePanel> */}
{/* <ResizableHandle withHandle /> */}
{/* <ResizablePanel defaultSize={50}> */}
<ErrorBoundary FallbackComponent={PreviewErrorFallback}>
<div
className={cn(
"bg-white text-black p-4 fixed left-0 h-[calc(100vh-59px)] w-screen transition-transform translate-x-[200%]",
activeMobileView === "tutorial"
? "translate-x-[200%]"
: activeMobileView === "code"
? "translate-x-[100%]"
: activeMobileView === "output"
? "translate-x-0"
: "",
)}
>
{lang === "react" ? (
<Preview
componentName={componentName}
tutorialCode={tutorial?.code || ""}
/>
) : (
<Output
// @ts-ignore
codeValue={codeValue || tutorial?.code || ""}
// codeValue={codeValue || CODE_SNIPPETS[language]}
// language={language}
language={lang}
/>
)}
</div>
</ErrorBoundary>
{/* </ResizablePanel> */}
{/* </ResizablePanelGroup> */}
</div>
<div className="hidden md:block h-[calc(100vh-55px)]">
<ResizablePanelGroup direction="vertical" className="border-r">
<ResizablePanel defaultSize={50}>
<div className="h-full ">
<div className="p-2 flex gap-4">
<ThemeDropdown
handleThemeChange={handleThemeChange}
theme={theme}
/>
{/* <LanguagesDropdown
handleLanguageChange={handleLanguageChange}
language={lang}
/> */}
</div>
<div className="h-full">
<CodeEditor
codeValue={codeValue}
// @ts-ignore
// defaultCode={CODE_SNIPPETS[language]}
defaultCode={tutorial?.code || ""}
onChange={handleCodeChange}
theme={theme}
// language={language}
language={lang}
/>
</div>
</div>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel defaultSize={50}>
<ErrorBoundary FallbackComponent={PreviewErrorFallback}>
<div className="bg-white text-black h-full p-4">
{lang === "react" ? (
<Preview
componentName={componentName}
tutorialCode={tutorial?.code || ""}
/>
) : (
<Output
// @ts-ignore
codeValue={codeValue || tutorial?.code || ""}
// codeValue={codeValue || CODE_SNIPPETS[language]}
// language={language}
language={lang}
/>
)}
</div>
</ErrorBoundary>
</ResizablePanel>
</ResizablePanelGroup>
</div>
</>
);
}