fix : comflic

This commit is contained in:
math-pixel
2026-04-29 10:51:40 +02:00
128 changed files with 10190 additions and 12922 deletions
+12
View File
@@ -0,0 +1,12 @@
import { useContext } from "react";
import { DocsLanguageContext } from "@/contexts/docs/DocsLanguageContext";
export function useDocsLanguage() {
const context = useContext(DocsLanguageContext);
if (!context) {
throw new Error("useDocsLanguage must be used inside DocsLanguageProvider");
}
return context;
}
+164
View File
@@ -0,0 +1,164 @@
import { useCallback, useRef, useState } from "react";
import type { MapNode, SceneData } from "@/types/editor";
interface ObjectTransform {
uuid: string;
position: { x: number; y: number; z: number };
rotation: { x: number; y: number; z: number };
scale: { x: number; y: number; z: number };
}
class HistoryManager {
private history: ObjectTransform[][] = [];
private currentIndex = -1;
private maxSize: number;
constructor(maxSize = 50) {
this.maxSize = maxSize;
}
saveSnapshot(objects: ObjectTransform[]): void {
if (this.currentIndex < this.history.length - 1) {
this.history = this.history.slice(0, this.currentIndex + 1);
}
this.history.push(objects.map((object) => ({ ...object })));
this.currentIndex = this.history.length - 1;
if (this.history.length > this.maxSize) {
this.history.shift();
this.currentIndex--;
}
}
undo(): ObjectTransform[] | undefined {
if (this.currentIndex <= 0) return undefined;
this.currentIndex--;
return this.history[this.currentIndex];
}
redo(): ObjectTransform[] | undefined {
if (this.currentIndex >= this.history.length - 1) return undefined;
this.currentIndex++;
return this.history[this.currentIndex];
}
getUndoCount(): number {
return this.currentIndex;
}
getRedoCount(): number {
return this.history.length - 1 - this.currentIndex;
}
}
interface UseEditorHistoryResult {
undoCount: number;
redoCount: number;
handleUndo: () => void;
handleRedo: () => void;
handleTransformStart: () => void;
handleTransformEnd: () => void;
}
export function useEditorHistory(
sceneData: SceneData | null,
setSceneData: React.Dispatch<React.SetStateAction<SceneData | null>>,
): UseEditorHistoryResult {
const [undoCount, setUndoCount] = useState(0);
const [redoCount, setRedoCount] = useState(0);
const historyManager = useRef(new HistoryManager(50));
const updateHistoryCounts = useCallback(() => {
setUndoCount(historyManager.current.getUndoCount());
setRedoCount(historyManager.current.getRedoCount());
}, []);
const applySnapshot = useCallback(
(snapshot: ObjectTransform[]): void => {
setSceneData((prev) => {
if (!prev) return null;
const mapNodes = prev.mapNodes.map((node, index) => {
const transform = snapshot.find(
(item) => item.uuid === `node-${index}`,
);
if (!transform) return node;
return {
...node,
position: [
transform.position.x,
transform.position.y,
transform.position.z,
],
rotation: [
transform.rotation.x,
transform.rotation.y,
transform.rotation.z,
],
scale: [transform.scale.x, transform.scale.y, transform.scale.z],
} satisfies MapNode;
});
return { ...prev, mapNodes };
});
},
[setSceneData],
);
const handleUndo = useCallback(() => {
const snapshot = historyManager.current.undo();
if (!snapshot) return;
applySnapshot(snapshot);
updateHistoryCounts();
}, [applySnapshot, updateHistoryCounts]);
const handleRedo = useCallback(() => {
const snapshot = historyManager.current.redo();
if (!snapshot) return;
applySnapshot(snapshot);
updateHistoryCounts();
}, [applySnapshot, updateHistoryCounts]);
const handleTransformStart = useCallback(() => {
if (!sceneData) return;
historyManager.current.saveSnapshot(createSnapshot(sceneData));
}, [sceneData]);
const handleTransformEnd = useCallback(() => {
if (!sceneData) return;
historyManager.current.saveSnapshot(createSnapshot(sceneData));
updateHistoryCounts();
}, [sceneData, updateHistoryCounts]);
return {
undoCount,
redoCount,
handleUndo,
handleRedo,
handleTransformStart,
handleTransformEnd,
};
}
function createSnapshot(sceneData: SceneData): ObjectTransform[] {
return sceneData.mapNodes.map((node, index) => ({
uuid: `node-${index}`,
position: {
x: node.position[0],
y: node.position[1],
z: node.position[2],
},
rotation: {
x: node.rotation[0],
y: node.rotation[1],
z: node.rotation[2],
},
scale: { x: node.scale[0], y: node.scale[1], z: node.scale[2] },
}));
}
+65
View File
@@ -0,0 +1,65 @@
import { useCallback, useEffect, useState } from "react";
import { createSceneDataFromFiles } from "@/utils/editor/loadEditorScene";
import { loadMapSceneData } from "@/utils/loadMapSceneData";
import type { SceneData } from "@/types/editor";
interface UseEditorSceneDataResult {
hasMapJson: boolean;
isMapLoading: boolean;
sceneData: SceneData | null;
setSceneData: React.Dispatch<React.SetStateAction<SceneData | null>>;
handleFolderUpload: (
event: React.ChangeEvent<HTMLInputElement>,
) => Promise<void>;
}
export function useEditorSceneData(): UseEditorSceneDataResult {
const [hasMapJson, setHasMapJson] = useState<boolean>(false);
const [isMapLoading, setIsMapLoading] = useState<boolean>(true);
const [sceneData, setSceneData] = useState<SceneData | null>(null);
useEffect(() => {
const loadScene = async (): Promise<void> => {
setIsMapLoading(true);
try {
const loadedSceneData = await loadMapSceneData();
setSceneData(loadedSceneData);
setHasMapJson(Boolean(loadedSceneData));
} catch (error) {
console.error("Error loading map data:", error);
setHasMapJson(false);
} finally {
setIsMapLoading(false);
}
};
loadScene();
}, []);
const handleFolderUpload = useCallback(
async (event: React.ChangeEvent<HTMLInputElement>): Promise<void> => {
const files = event.target.files;
if (!files) return;
try {
const uploadedSceneData = await createSceneDataFromFiles(files);
setSceneData(uploadedSceneData);
setHasMapJson(true);
} catch (error) {
const message = error instanceof Error ? error.message : "Erreur";
console.error("Error processing upload:", error);
alert(message);
}
},
[],
);
return {
hasMapJson,
isMapLoading,
sceneData,
setSceneData,
handleFolderUpload,
};
}
+1 -1
View File
@@ -1,5 +1,5 @@
import { useSyncExternalStore } from "react";
import { InteractionManager } from "@/stateManager/InteractionManager";
import { InteractionManager } from "@/managers/InteractionManager";
import type { InteractionSnapshot } from "@/types/interaction";
const manager = InteractionManager.getInstance();
+7 -2
View File
@@ -2,14 +2,19 @@ import { useEffect, useRef } from "react";
import type { RefObject } from "react";
import type { Object3D } from "three";
import { Octree } from "three/addons/math/Octree.js";
import type { OctreeReadyHandler } from "@/types/3d";
import type { OctreeReadyHandler } from "@/types/three";
export function useOctreeGraphNode(
graphNodeRef: RefObject<Object3D | null>,
onOctreeReady: OctreeReadyHandler,
rebuildKey: string | number = 0,
): void {
const octreeBuilt = useRef(false);
useEffect(() => {
octreeBuilt.current = false;
}, [rebuildKey]);
useEffect(() => {
const graphNode = graphNodeRef.current;
if (octreeBuilt.current || !graphNode) return;
@@ -20,5 +25,5 @@ export function useOctreeGraphNode(
const octree = new Octree();
octree.fromGraphNode(graphNode);
onOctreeReady(octree);
}, [graphNodeRef, onOctreeReady]);
}, [graphNodeRef, onOctreeReady, rebuildKey]);
}