skilld-frontend/src/app/(dashboard)/dashboard/(task)/task/[...taskId]/page.tsx

171 lines
5.7 KiB
TypeScript

import React from "react";
import { ScrollArea } from "@/components/ui/scroll-area";
import {
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
} from "@/components/ui/resizable";
import { unified } from "unified";
import remarkParse from "remark-parse";
import remarkRehype from "remark-rehype";
import rehypeStringify from "rehype-stringify";
import rehypePrettyCode from "rehype-pretty-code";
import markdownStyles from "@/styles/markdown-styles.module.css";
import { tutorialData } from "@/constants/tutorial-data";
import { notFound } from "next/navigation";
import { buttonVariants } from "@/components/ui/button";
import Link from "next/link";
import { cn } from "@/lib/utils";
import EditorWindow from "@/components/task/editor-window";
import { LANGUAGE_VERSIONS } from "@/constants/language-options";
async function main(tutorialCode: string) {
const file = await unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypePrettyCode, {})
.use(rehypeStringify)
.process(tutorialCode);
return file;
}
const languages = Object.keys(LANGUAGE_VERSIONS);
const Page = async ({ params }: { params: { taskId: string[] } }) => {
if (!params.taskId[0] || !languages.includes(params.taskId[0])) {
notFound();
}
const langTutorial = tutorialData.find(
(t) => t.language === params.taskId[0],
)!;
const tutorial = langTutorial.tutorial.find(
(t) => t.id === (Number(params.taskId[1]) || 1),
);
const tutorialIndex = langTutorial.tutorial.findIndex(
(t) => t.id === (Number(params.taskId[1]) || 1),
);
if (!tutorial || tutorialIndex === -1) {
notFound();
}
const code = await main(tutorial?.content || "");
return (
<>
<div className="md:hidden w-full h-full">
<ResizablePanelGroup
direction="vertical"
className="max-w-[1440px] mx-auto h-full"
>
<ResizablePanel defaultSize={50}>
<ScrollArea className="h-[calc(100vh-55px)] border-b">
<div className="px-4 py-6 flex flex-col gap-4 h-full mb-[50vh]">
<div
className={cn("grow", markdownStyles["markdown"])}
dangerouslySetInnerHTML={{ __html: String(code) }}
></div>
<div className="flex justify-between">
<div className="mb-6">
{langTutorial?.tutorial[tutorialIndex - 1] && (
<Link
href={`/dashboard/task/${params.taskId[0]}/${
Number(params.taskId[1]) - 1
}`}
className={buttonVariants({
variant: "outline",
})}
>
Prev
</Link>
)}
</div>
<div className="mb-6">
{langTutorial?.tutorial[tutorialIndex + 1] && (
<Link
href={`/dashboard/task/${params.taskId[0]}/${
Number(params.taskId[1]) + 1
}`}
className={buttonVariants({ variant: "outline" })}
>
Next
</Link>
)}
</div>
</div>
</div>
</ScrollArea>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel defaultSize={50}>
<EditorWindow
language={params.taskId[0]}
step={Number(params.taskId[1]) || 1}
/>
</ResizablePanel>
</ResizablePanelGroup>
</div>
<div className="hidden md:block w-full h-full">
<ResizablePanelGroup
direction="horizontal"
className="max-w-[1440px] mx-auto h-full"
>
<ResizablePanel defaultSize={50}>
<ScrollArea className="h-[calc(100vh-55px)]">
<div className="px-4 py-6 flex flex-col gap-4 h-full">
<div
className={cn("grow", markdownStyles["markdown"])}
dangerouslySetInnerHTML={{ __html: String(code) }}
></div>
<div className="flex justify-between">
<div className="mb-6">
{langTutorial?.tutorial[tutorialIndex - 1] && (
<Link
href={`/dashboard/task/${params.taskId[0]}/${
Number(params.taskId[1]) - 1
}`}
className={buttonVariants({
variant: "outline",
})}
>
Prev
</Link>
)}
</div>
<div className="mb-6">
{langTutorial?.tutorial[tutorialIndex + 1] && (
<Link
href={`/dashboard/task/${params.taskId[0]}/${
Number(params.taskId[1]) + 1
}`}
className={buttonVariants({ variant: "outline" })}
>
Next
</Link>
)}
</div>
</div>
</div>
</ScrollArea>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel defaultSize={50}>
<EditorWindow
language={params.taskId[0]}
step={Number(params.taskId[1]) || 1}
/>
</ResizablePanel>
</ResizablePanelGroup>
</div>
</>
);
};
export default Page;