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"),