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 */} + { + const container = document.getElementById("canvas-container"); + if (container) { + container.requestFullscreen().catch((err) => { + toast.error("Não foi possível entrar em tela cheia: " + err.message); + }); + } + }} + className="flex h-7 w-full items-center justify-center gap-1 rounded border border-primary/40 bg-background/40 font-mono text-[10px] uppercase tracking-widest text-primary hover:bg-primary/10 transition-colors" + title="Entrar em modo tela cheia" + > + 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 ? ( + + + + Centralizar + + + + Retornar (ESC) + + + ) : ( + <> + {/* Botão de Toggle do Sidebar */} + setSidebarOpen(!sidebarOpen)} + className={`absolute z-30 h-8 w-8 rounded-md bg-background/80 border-primary/30 text-primary shadow-md hover:bg-primary/10 transition-all duration-300 ${ + sidebarOpen ? "right-[332px]" : "right-4" + } top-[205px]`} + title={sidebarOpen ? "Recolher menu" : "Expandir menu"} + > + + + + + + + > + )} {/* Side panel */} -