Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"cSpell.words": [
"sonner"
]
}
71 changes: 71 additions & 0 deletions app/api/template/[id]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { db } from "@/lib/db";
import path from "path";
import fs from "fs/promises";
import { NextRequest } from "next/server";
import {
readTemplateStructureFromJson,
saveTemplateStructureToJson,
} from "@/features/playground/libs/path-to-json";
import { templatePaths } from "@/template";

function validateJsonStructure(data: unknown): boolean {
try {
JSON.parse(JSON.stringify(data));
return true;
} catch (error) {
console.error("Invalid JSON structures", error);
return false;
}
}

export async function GET(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params;
if (!id) {
return Response.json({ error: "Missing playground ID" }, { status: 400 });
}

const playground = await db.playground.findUnique({
where: {
id,
},
});
if (!playground) {
return Response.json({ error: "Playground not found" }, { status: 404 });
}

const templateKey = playground.template as keyof typeof templatePaths;
const templatePath = templatePaths[templateKey];

if (!templatePath) {
return Response.json({ error: "Invalid template" }, { status: 404 });
}

try {
const inputPath = path.join(process.cwd(), templatePath);
const outputFile = path.join(process.cwd(), `output/${templateKey}.json`);

await saveTemplateStructureToJson(inputPath, outputFile);
const result = await readTemplateStructureFromJson(outputFile);

if (!validateJsonStructure(result.items)) {
return Response.json(
{ error: "Invalid JSON structure" },
{ status: 500 }
);
}
await fs.unlink(outputFile);
return Response.json(
{ success: true, templateJson: result },
{ status: 200 }
);
} catch (error) {
console.error("Error generating template JSON:", error);
return Response.json(
{ error: "Failed to generate template" },
{ status: 500 }
);
}
}
13 changes: 13 additions & 0 deletions app/playground/[id]/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { SidebarProvider } from "../../../components/ui/sidebar"

export default function PlaygroundLayout({
children,
}: {
children: React.ReactNode
}){
return (
<SidebarProvider>
{children}
</SidebarProvider>
)
}
57 changes: 57 additions & 0 deletions app/playground/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"use client";

import { useParams } from "next/navigation";
import { TooltipProvider } from "../../../components/ui/tooltip";
import { SidebarInset, SidebarTrigger } from "@/components/ui/sidebar";
import { Separator } from "@/components/ui/separator";
import { usePlayground } from "@/features/playground/hooks/usePlayground";
import { TemplateFileTree } from "@/features/playground/components/template-file-tree";
import { useFileExplorer } from "@/features/playground/hooks/useFileExplorer";

const PlaygroundPage = () => {
const { id } = useParams<{ id: string }>();
const {playgroundData, templateData, isLoading, error, saveTemplateData} = usePlayground(id)
const {
activeFileId,
closeAllFiles,
openFile,
closeFile,
editorContent,
updateFileContent,
handleAddFile,
handleAddFolder,
handleDeleteFile,
handleDeleteFolder,
handleRenameFile,
handleRenameFolder,
openFiles,
setTemplateData,
setActiveFileId,
setPlaygroundId,
setOpenFiles,
} = useFileExplorer();

return (
<div>
<>
<TemplateFileTree
data={templateData}
/>
<SidebarInset>
<header className="flex h-16 shrink-0 items-center gap-2 border-bottom px-4">
<SidebarTrigger className="-ml-1">
<Separator className="mr-2 h-4" orientation="vertical" />
<div className="flex flex-1 items-center gap-2">
<div className="flex flex-col flex-1">
{playgroundData?.title || 'Code Playground'}
</div>
</div>
</SidebarTrigger>
</header>
</SidebarInset>
</>
</div>
);
};

export default PlaygroundPage;
48 changes: 48 additions & 0 deletions features/playground/actions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"use server";

import { currentUser } from "@/features/auth/actions";
import db from "@/lib/db";
import { TemplateFolder } from "../libs/path-to-json";


export const getPlaygroundById = async (id: string) => {
try {
const playground = await db.playground.findUnique({
where: { id },
select: {
title: true,
description: true,
templateFiles: {
select: {
content: true,
},
},
},
});
return playground;
} catch (error) {
console.log(error);
}
};

export const SaveUpdatedCode = async(playgroundId: string, data: TemplateFolder) => {
const user = await currentUser()
if(!user) return null;

try{
const updatedPlayground = await db.templateFile.upsert({
where: {
playgroundId
},
update: {
content: JSON.stringify(data)
},
create: {
playgroundId,
content: JSON.stringify(data)
}
})
}catch(error){

}
}
Loading