diff --git a/src/components/ViewCube.tsx b/src/components/ViewCube.tsx index e34d6ed..7fbd117 100644 --- a/src/components/ViewCube.tsx +++ b/src/components/ViewCube.tsx @@ -13,7 +13,7 @@ import { } from './three/viewCubeBus'; import { useModelStore } from '@/stores/useModelStore'; import { getModelLocalGroup } from '@/lib/modelTransforms'; -import { Check, RotateCcw } from 'lucide-react'; +import { Check, RotateCcw, Maximize2 } from 'lucide-react'; import { toast } from 'sonner'; /** Builds a square canvas texture with a label centered on it. */ @@ -296,6 +296,23 @@ export function ViewCube() { reset )} + + {/* Botão de Tela Cheia */} + ); } diff --git a/src/pages/Viewer.tsx b/src/pages/Viewer.tsx index 07835c1..8482d64 100644 --- a/src/pages/Viewer.tsx +++ b/src/pages/Viewer.tsx @@ -1,6 +1,6 @@ import { useNavigate, useSearchParams } from "react-router-dom"; import { supabase } from "@/integrations/supabase/client"; -import { ArrowLeft, Glasses, Box, Ruler, FileText, Upload, Loader2, Users } from "lucide-react"; +import { ArrowLeft, Glasses, Box, Ruler, FileText, Upload, Loader2, Users, Menu, Target } from "lucide-react"; import { Button } from "@/components/ui/button"; import { useModelStore } from "@/stores/useModelStore"; import { ModelViewerCanvas } from "@/components/three/ModelViewer"; @@ -21,6 +21,7 @@ import { Separator } from "@/components/ui/separator"; import { getSupportedExtension, convertToGLB, ACCEPTED_EXTENSIONS } from "@/lib/convertToGLB"; import { validateModelFile } from "@/lib/validateModelFile"; import { convertIFCtoGLB } from "@/lib/convertIFC"; +import { mainCameraRef, mainControlsRef } from "@/components/three/viewCubeBus"; const Viewer = () => { const navigate = useNavigate(); @@ -39,6 +40,44 @@ const Viewer = () => { const fileInputRef = useRef(null); const [converting, setConverting] = useState(false); + const [isFullscreen, setIsFullscreen] = useState(false); + const [sidebarOpen, setSidebarOpen] = useState(true); + + useEffect(() => { + const handleFullscreenChange = () => { + setIsFullscreen(!!document.fullscreenElement); + }; + document.addEventListener("fullscreenchange", handleFullscreenChange); + return () => { + document.removeEventListener("fullscreenchange", handleFullscreenChange); + }; + }, []); + + const handleRecenter = useCallback(() => { + const camera = mainCameraRef.current; + const controls = mainControlsRef.current; + if (camera) { + camera.position.set(2, 2, 2); + camera.up.set(0, 1, 0); + camera.lookAt(0, 0, 0); + } + if (controls) { + // @ts-ignore + controls.target.set(0, 0, 0); + // @ts-ignore + controls.update(); + } + toast.success("Visualização centralizada"); + }, []); + + const exitFullscreen = useCallback(() => { + if (document.fullscreenElement) { + document.exitFullscreen().catch((err) => { + console.error("Erro ao sair de tela cheia:", err); + }); + } + }, []); + const [searchParams] = useSearchParams(); const roomId = searchParams.get("room"); const channelRef = useRef | null>(null); @@ -325,15 +364,51 @@ const Viewer = () => {
{/* 3D Canvas with floating controls */} -
+
- - - + {isFullscreen ? ( +
+ + +
+ ) : ( + <> + {/* Botão de Toggle do Sidebar */} + + + + + + + )}
{/* Side panel */} -