Pantalla completa

This commit is contained in:
Your Name
2025-03-05 09:57:05 -06:00
parent cffba7b327
commit e997fc05d2

View File

@@ -4,7 +4,7 @@ import type { OrbitControls as OrbitControlsImpl } from 'three-stdlib';
import { Canvas } from "@react-three/fiber"; import { Canvas } from "@react-three/fiber";
import { useGLTF, useAnimations, Environment, Loader, OrbitControls, Html } from "@react-three/drei"; import { useGLTF, useAnimations, Environment, Loader, OrbitControls, Html } from "@react-three/drei";
import { Suspense, useEffect, useRef, useState } from "react"; import { Suspense, useEffect, useRef, useState } from "react";
import { RotateCw, Play, Pause, Film, ListTree } from "lucide-react"; import { RotateCw, Play, Pause, Film, ListTree, Shrink, Expand } from "lucide-react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { import {
Popover, Popover,
@@ -14,6 +14,7 @@ import {
import { ScrollArea } from "@/components/ui/scroll-area"; import { ScrollArea } from "@/components/ui/scroll-area";
// Model component // Model component
function Model({ url, position, rotation, scale, onAnimationsLoaded, onNodesLoaded }: { function Model({ url, position, rotation, scale, onAnimationsLoaded, onNodesLoaded }: {
url: string; url: string;
@@ -56,7 +57,7 @@ function Model({ url, position, rotation, scale, onAnimationsLoaded, onNodesLoad
); );
} }
// Preload the model // Preload the model
useGLTF.preload("/3d/motor_de_combustion/scene.gltf"); // useGLTF.preload("/3d/motor_de_combustion/scene.gltf");
const InitialParams = { const InitialParams = {
position: [0, -2, 0] as [number, number, number], position: [0, -2, 0] as [number, number, number],
@@ -67,12 +68,14 @@ const InitialParams = {
// Main 3D Viewer // Main 3D Viewer
export default function Previewer({ modelUrl }: { modelUrl: string }) { export default function Previewer({ modelUrl }: { modelUrl: string }) {
const controlsRef = useRef<OrbitControlsImpl>(null); const controlsRef = useRef<OrbitControlsImpl>(null);
const containerRef = useRef<HTMLDivElement>(null);
const [animations, setAnimations] = useState<string[]>([]); const [animations, setAnimations] = useState<string[]>([]);
const [actions, setActions] = useState<Record<string, any>>({}); const [actions, setActions] = useState<Record<string, any>>({});
const [currentAnimation, setCurrentAnimation] = useState<string | null>(null); const [currentAnimation, setCurrentAnimation] = useState<string | null>(null);
const [nodes, setNodes] = useState<string[]>([]); const [nodes, setNodes] = useState<string[]>([]);
const [nodePositions, setNodePositions] = useState<Record<string, [number, number, number]>>({}); const [nodePositions, setNodePositions] = useState<Record<string, [number, number, number]>>({});
const [isFullscreen, setIsFullscreen] = useState(false);
const resetView = () => { const resetView = () => {
@@ -96,8 +99,26 @@ export default function Previewer({ modelUrl }: { modelUrl: string }) {
} }
}; };
// Handle Fullscreen Mode
const toggleFullscreen = () => {
if (!document.fullscreenElement) {
containerRef.current?.requestFullscreen().then(() => {
setIsFullscreen(true);
}).catch(err => {
console.error("Error entering fullscreen:", err);
});
} else {
document.exitFullscreen().then(() => {
setIsFullscreen(false);
}).catch(err => {
console.error("Error exiting fullscreen:", err);
});
}
};
return ( return (
<div className="relative w-full grow bg-white/10 shadow-xl shadow-gray-300/25 rounded-lg p-6 backdrop-blur-lg h-100"> <div ref={containerRef} className="relative w-full grow bg-white/10 shadow-xl shadow-gray-300/25 rounded-lg p-6 backdrop-blur-lg h-100">
<div className="z-10 absolute top-4 w-100 flex wrap gap-5"> <div className="z-10 absolute top-4 w-100 flex wrap gap-5">
<Popover> <Popover>
<PopoverTrigger className="flex items-center gap-2 bg-gradient-to-r from-blue-600 to-blue-800 text-white px-4 py-2 rounded-lg shadow-lg transition-all duration-300 hover:from-blue-500 hover:to-blue-700"> <PopoverTrigger className="flex items-center gap-2 bg-gradient-to-r from-blue-600 to-blue-800 text-white px-4 py-2 rounded-lg shadow-lg transition-all duration-300 hover:from-blue-500 hover:to-blue-700">
@@ -105,7 +126,7 @@ export default function Previewer({ modelUrl }: { modelUrl: string }) {
<span>Animaciones</span> <span>Animaciones</span>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent className="p-4 bg-blue-900 text-white w-64 my-5 mx-15"> <PopoverContent className="p-4 bg-blue-900 text-white w-64">
<ScrollArea className="max-h-60"> <ScrollArea className="max-h-60">
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
{animations.length > 0 ? ( {animations.length > 0 ? (
@@ -138,7 +159,7 @@ export default function Previewer({ modelUrl }: { modelUrl: string }) {
<ListTree /> <ListTree />
Partes del modelo Partes del modelo
</PopoverTrigger> </PopoverTrigger>
<PopoverContent className="p-4 bg-blue-50 text-white w-64 my-5 mx-15"> <PopoverContent className="p-4 bg-blue-50 text-white w-64">
<ScrollArea className="max-h-60"> <ScrollArea className="max-h-60">
<div className="flex flex-col gap-2"> <div className="flex flex-col gap-2">
{nodes.length > 0 ? ( {nodes.length > 0 ? (
@@ -155,17 +176,23 @@ export default function Previewer({ modelUrl }: { modelUrl: string }) {
</PopoverContent> </PopoverContent>
</Popover> </Popover>
</div> </div>
{/* Reset Camera Button */} <div className="absolute bottom-4 right-4 z-10 flex gap-4">
<div className="absolute bottom-4 right-4 z-10">
<Button <Button
className="bg-gradient-to-r from-red-600 to-red-800 w-40 text-white px-5 py-3 rounded-lg shadow-lg transition-all duration-300 hover:from-red-500 hover:to-red-700 active:scale-95 flex items-center gap-2 justify-center" className="bg-gradient-to-r from-red-600 to-red-800 w-40 text-white px-5 py-3 rounded-lg shadow-lg transition-all duration-300 hover:from-red-500 hover:to-red-700 active:scale-95 flex items-center gap-2 justify-center"
onClick={resetView} onClick={resetView}
> >
<RotateCw className="w-5 h-5" /> <RotateCw className="w-5 h-5" />
Reset Camera Centrar cámara
</Button>
{/* Botón de pantalla completa */}
<Button
className="bg-gradient-to-r from-gray-700 to-gray-900 w-40 text-white px-5 py-3 rounded-lg shadow-lg transition-all duration-300 hover:from-gray-600 hover:to-gray-800 active:scale-95 flex items-center gap-2 justify-center"
onClick={toggleFullscreen} >
{isFullscreen ? <Shrink className="w-5 h-5" /> : <Expand className="w-5 h-5" />}
{isFullscreen ? "Salir" : "Pantalla Completa"}
</Button> </Button>
</div> </div>
<div className="w-full h-full"> <div className="w-full h-full">
<Suspense fallback={<Loader />}> <Suspense fallback={<Loader />}>
<Canvas camera={{ position: [0, 0, 12], fov: 20 }}> <Canvas camera={{ position: [0, 0, 12], fov: 20 }}>