From 6b8ba3d58dc6b61fbf353128dd24c9a232488cf6 Mon Sep 17 00:00:00 2001 From: math-pixel <59537610+math-pixel@users.noreply.github.com> Date: Thu, 23 Apr 2026 15:40:10 +0200 Subject: [PATCH] feat : save map.json on project --- public/map.json | 56 +++++++++++++++++++----- src/components/editor/EditorControls.tsx | 8 ++++ src/components/editor/EditorPage.css | 17 +++++++ src/components/editor/EditorPage.tsx | 23 ++++++++++ vite.config.ts | 29 +++++++++++- 5 files changed, 122 insertions(+), 11 deletions(-) diff --git a/public/map.json b/public/map.json index 62cb16c..21826f1 100644 --- a/public/map.json +++ b/public/map.json @@ -2,22 +2,58 @@ { "name": "test_cube", "type": "Mesh", - "position": [0, 5, 0], - "rotation": [0, 0, 0], - "scale": [2, 2, 2] + "position": [ + 0, + 5, + 0 + ], + "rotation": [ + 0, + 0, + 0 + ], + "scale": [ + 2, + 2, + 2 + ] }, { "name": "test_sphere", "type": "Mesh", - "position": [10, 5, 0], - "rotation": [0, 0, 0], - "scale": [3, 3, 3] + "position": [ + -35.67436887305092, + -12.343540259022419, + 0 + ], + "rotation": [ + 0, + 0, + 0 + ], + "scale": [ + 3, + 3, + 3 + ] }, { "name": "test_cylinder", "type": "Mesh", - "position": [-10, 5, 0], - "rotation": [0, 0, 0], - "scale": [1, 4, 1] + "position": [ + -10, + 5, + 0 + ], + "rotation": [ + 0, + 0, + 0 + ], + "scale": [ + 1, + 4, + 1 + ] } -] +] \ No newline at end of file diff --git a/src/components/editor/EditorControls.tsx b/src/components/editor/EditorControls.tsx index 669cb78..e313046 100644 --- a/src/components/editor/EditorControls.tsx +++ b/src/components/editor/EditorControls.tsx @@ -11,6 +11,7 @@ interface EditorControlsProps { onUndo: () => void; onRedo: () => void; onExportJson: () => void; + onSaveToServer?: () => void; onResetCamera?: () => void; onPlayerMode?: () => void; isPlayerMode?: boolean; @@ -27,6 +28,7 @@ export default function EditorControls({ onUndo, onRedo, onExportJson, + onSaveToServer, onResetCamera, onPlayerMode, isPlayerMode, @@ -89,6 +91,12 @@ export default function EditorControls({ 💾 Export JSON + {onSaveToServer && ( + + )} +

View

{onResetCamera && ( diff --git a/src/components/editor/EditorPage.css b/src/components/editor/EditorPage.css index 9ae97fc..6d95225 100644 --- a/src/components/editor/EditorPage.css +++ b/src/components/editor/EditorPage.css @@ -236,6 +236,23 @@ code { background: #ff8533; } +.save-button { + width: 100%; + margin-top: 10px; + padding: 12px; + background: #22c55e; + color: white; + border: none; + border-radius: 6px; + cursor: pointer; + font-size: 14px; + font-weight: bold; +} + +.save-button:hover { + background: #16a34a; +} + .reset-button { width: 100%; padding: 12px; diff --git a/src/components/editor/EditorPage.tsx b/src/components/editor/EditorPage.tsx index 5ff6a67..b7b0f81 100644 --- a/src/components/editor/EditorPage.tsx +++ b/src/components/editor/EditorPage.tsx @@ -145,6 +145,28 @@ export function EditorPage(): React.JSX.Element { } }, [applySnapshot]); + const handleSaveToServer = useCallback(async () => { + if (!sceneData) return; + const json = JSON.stringify(sceneData.mapNodes, null, 2); + + try { + const response = await fetch("/api/save-map", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: json, + }); + + if (response.ok) { + alert("Map enregistrée avec succès!"); + } else { + alert("Erreur lors de l'enregistrement"); + } + } catch (err) { + console.error("Error saving map:", err); + alert("Erreur lors de l'enregistrement"); + } + }, [sceneData]); + const handleExportJson = useCallback(() => { if (!sceneData) return; const json = JSON.stringify(sceneData.mapNodes, null, 2); @@ -406,6 +428,7 @@ export function EditorPage(): React.JSX.Element { onUndo={handleUndo} onRedo={handleRedo} onExportJson={handleExportJson} + onSaveToServer={handleSaveToServer} onResetCamera={handleResetCamera} onPlayerMode={handlePlayerMode} isPlayerMode={isPlayerMode} diff --git a/vite.config.ts b/vite.config.ts index d779ded..4078792 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,10 +1,37 @@ import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; import path from "node:path"; +import fs from "node:fs"; +import type { ViteDevServer } from "vite"; + +const saveMapPlugin = () => ({ + name: "save-map-api", + configureServer(server: ViteDevServer) { + server.middlewares.use("/api/save-map", async (req: any, res: any) => { + if (req.method !== "POST") { + res.writeHead(405).end(); + return; + } + + let body = ""; + req.on("data", (chunk: any) => (body += chunk)); + req.on("end", () => { + try { + const mapPath = path.resolve(__dirname, "public/map.json"); + fs.writeFileSync(mapPath, body); + res.writeHead(200, { "Content-Type": "application/json" }); + res.end(JSON.stringify({ success: true })); + } catch (err: any) { + res.writeHead(500).end(JSON.stringify({ error: err.message })); + } + }); + }); + }, +}); // https://vite.dev/config/ export default defineConfig({ - plugins: [react()], + plugins: [react(), saveMapPlugin()], resolve: { alias: { "@": path.resolve(__dirname, "./src"),