From 3882e8c338165e16fde49c3294728123259113c4 Mon Sep 17 00:00:00 2001 From: Marcos Reifonas Date: Mon, 21 Sep 2026 01:48:01 +0000 Subject: [PATCH] fix(viewer3d): harmonize ViewCube container background and ISO button for light mode --- src/components/viewer3d/ViewCube.tsx | 78 ++++++++++++++++++---------- 1 file changed, 52 insertions(+), 26 deletions(-) diff --git a/src/components/viewer3d/ViewCube.tsx b/src/components/viewer3d/ViewCube.tsx index f4dacc1..7f7ff24 100644 --- a/src/components/viewer3d/ViewCube.tsx +++ b/src/components/viewer3d/ViewCube.tsx @@ -13,6 +13,7 @@ export const ViewCube: React.FC = ({ onSelectView, mainCameraRef const sceneRef = useRef(null); const cameraRef = useRef(null); const cubeRef = useRef(null); + const wireframeRef = useRef(null); const raycasterRef = useRef(new THREE.Raycaster()); const mouseRef = useRef(new THREE.Vector2()); @@ -39,7 +40,7 @@ export const ViewCube: React.FC = ({ onSelectView, mainCameraRef camera.lookAt(0, 0, 0); cameraRef.current = camera; - // 2. Renderer + // 2. Renderer Transparente const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); renderer.setSize(width, height); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); @@ -49,24 +50,24 @@ export const ViewCube: React.FC = ({ onSelectView, mainCameraRef containerRef.current.innerHTML = ''; containerRef.current.appendChild(renderer.domElement); - // 3. Helper to create high-res Canvas Texture for each face (SteelXR Style) - const createFaceTexture = (text: string) => { + // 3. Helper to create high-res Canvas Texture for each face + const createFaceTexture = (text: string, isDark: boolean) => { const canvas = document.createElement('canvas'); canvas.width = 256; canvas.height = 256; const ctx = canvas.getContext('2d'); if (ctx) { - // Background: Deep Dark Navy Blue (#0f172a / #1e293b) - ctx.fillStyle = '#0f172a'; + // Face Background: Azul petróleo equilibrado no claro (#1e293b) e escuro (#0f172a) + ctx.fillStyle = isDark ? '#0f172a' : '#1e293b'; ctx.fillRect(0, 0, 256, 256); - // Neon Cyan Border (#22d3ee) - ctx.strokeStyle = '#22d3ee'; + // Neon Cyan Border (#0891b2 no claro / #22d3ee no escuro) + ctx.strokeStyle = isDark ? '#22d3ee' : '#06b6d4'; ctx.lineWidth = 14; ctx.strokeRect(7, 7, 242, 242); // Inner soft cyan glow - ctx.strokeStyle = 'rgba(34, 211, 238, 0.4)'; + ctx.strokeStyle = isDark ? 'rgba(34, 211, 238, 0.4)' : 'rgba(6, 182, 212, 0.3)'; ctx.lineWidth = 6; ctx.strokeRect(18, 18, 220, 220); @@ -75,8 +76,8 @@ export const ViewCube: React.FC = ({ onSelectView, mainCameraRef ctx.font = 'bold 54px system-ui, -apple-system, sans-serif'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; - ctx.shadowColor = '#06b6d4'; - ctx.shadowBlur = 12; + ctx.shadowColor = isDark ? '#06b6d4' : '#0891b2'; + ctx.shadowBlur = isDark ? 12 : 8; ctx.fillText(text, 128, 128); } const texture = new THREE.CanvasTexture(canvas); @@ -84,15 +85,16 @@ export const ViewCube: React.FC = ({ onSelectView, mainCameraRef return texture; }; - // Faces Order in Three.js BoxGeometry: - // 0: Right (DIR), 1: Left (ESQ), 2: Top (TOPO), 3: Bottom (BASE), 4: Front (FRENTE), 5: Back (ATRÁS) + const isDarkMode = document.documentElement.classList.contains('dark'); + + // Faces: 0: Right (DIR), 1: Left (ESQ), 2: Top (TOPO), 3: Bottom (BASE), 4: Front (FRENTE), 5: Back (ATRÁS) const materials = [ - new THREE.MeshBasicMaterial({ map: createFaceTexture('DIR') }), - new THREE.MeshBasicMaterial({ map: createFaceTexture('ESQ') }), - new THREE.MeshBasicMaterial({ map: createFaceTexture('TOPO') }), - new THREE.MeshBasicMaterial({ map: createFaceTexture('BASE') }), - new THREE.MeshBasicMaterial({ map: createFaceTexture('FRENTE') }), - new THREE.MeshBasicMaterial({ map: createFaceTexture('ATRÁS') }), + new THREE.MeshBasicMaterial({ map: createFaceTexture('DIR', isDarkMode) }), + new THREE.MeshBasicMaterial({ map: createFaceTexture('ESQ', isDarkMode) }), + new THREE.MeshBasicMaterial({ map: createFaceTexture('TOPO', isDarkMode) }), + new THREE.MeshBasicMaterial({ map: createFaceTexture('BASE', isDarkMode) }), + new THREE.MeshBasicMaterial({ map: createFaceTexture('FRENTE', isDarkMode) }), + new THREE.MeshBasicMaterial({ map: createFaceTexture('ATRÁS', isDarkMode) }), ]; const geometry = new THREE.BoxGeometry(32, 32, 32); @@ -102,9 +104,32 @@ export const ViewCube: React.FC = ({ onSelectView, mainCameraRef // Glowing Neon Edges on the Cube const edges = new THREE.EdgesGeometry(geometry); - const lineMaterial = new THREE.LineBasicMaterial({ color: 0x22d3ee, linewidth: 2 }); + const lineMaterial = new THREE.LineBasicMaterial({ + color: isDarkMode ? 0x22d3ee : 0x06b6d4, + linewidth: 2, + }); const wireframe = new THREE.LineSegments(edges, lineMaterial); cube.add(wireframe); + wireframeRef.current = wireframe; + + // Função de atualização quando o tema mudar + const updateThemeMaterials = () => { + const dark = document.documentElement.classList.contains('dark'); + const labels = ['DIR', 'ESQ', 'TOPO', 'BASE', 'FRENTE', 'ATRÁS']; + materials.forEach((mat, idx) => { + if (mat.map) mat.map.dispose(); + mat.map = createFaceTexture(labels[idx], dark); + mat.needsUpdate = true; + }); + if (wireframeRef.current && wireframeRef.current.material) { + (wireframeRef.current.material as THREE.LineBasicMaterial).color.set(dark ? 0x22d3ee : 0x06b6d4); + } + }; + + const themeObserver = new MutationObserver(() => { + updateThemeMaterials(); + }); + themeObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['class'] }); // 4. Animation Loop: Sincroniza com a câmera principal em tempo real let animId: number; @@ -165,6 +190,7 @@ export const ViewCube: React.FC = ({ onSelectView, mainCameraRef return () => { cancelAnimationFrame(animId); dom.removeEventListener('click', handleCanvasClick); + themeObserver.disconnect(); materials.forEach((m) => { if (m.map) m.map.dispose(); m.dispose(); @@ -176,21 +202,21 @@ export const ViewCube: React.FC = ({ onSelectView, mainCameraRef return (
- {/* Container Reduzido (~70% do anterior) com estilo SteelXR */} -
- {/* Glow sutil */} -
+ {/* Container Reduzido (~70%) Harmonizado para Modo Claro e Escuro */} +
+ {/* Glow sutil harmonizado */} +
{/* Canvas WebGL 3D do Cubo Sincronizado */}
- {/* Botão ISO no canto inferior */} + {/* Botão ISO no canto inferior harmonizado com o tema */}
{/* Rótulo inferior */} - + Cubo 3D