From bcca3738d05560c12c3639b04f09a370da9713af Mon Sep 17 00:00:00 2001 From: Marcos Date: Fri, 10 Jul 2026 15:25:38 +0000 Subject: [PATCH] feat: improve dark mode contrast in Tower3D and IsolatedRoof3D components --- app/src/components/three/IsolatedRoof3D.tsx | 28 +++++++++++------ app/src/components/three/Tower3D.tsx | 35 +++++++++++++++------ app/src/lib/theme.tsx | 20 ++++++++++++ app/src/pages/IsolatedRoofModule.tsx | 4 +-- 4 files changed, 66 insertions(+), 21 deletions(-) diff --git a/app/src/components/three/IsolatedRoof3D.tsx b/app/src/components/three/IsolatedRoof3D.tsx index e0dd333..264e335 100644 --- a/app/src/components/three/IsolatedRoof3D.tsx +++ b/app/src/components/three/IsolatedRoof3D.tsx @@ -4,6 +4,7 @@ import * as THREE from 'three'; import SceneCanvas from '../SceneCanvas'; import FallbackDiagram from '../FallbackDiagram'; import { WindArrow } from './WindArrow'; +import { useCanvasTheme } from '@/lib/theme'; export interface IsolatedRoof3DInput { /** Tipo de cobertura: 'shed' (uma água) ou 'gable' (duas águas) */ @@ -43,6 +44,13 @@ function IsolatedRoofModel({ cpeLeeward, forceKN, }: IsolatedRoof3DInput) { + const theme = useCanvasTheme(); + const isDark = theme === 'dark'; + const labelColor = isDark ? '#cbd5e1' : '#475569'; + const textColor = isDark ? '#93c5fd' : '#1a202c'; + const lineMaterialColor = isDark ? '#94a3b8' : '#64748b'; + const pillarColor = isDark ? '#cbd5e1' : '#475569'; + const thetaRad = (theta * Math.PI) / 180; const halfDepth = depth / 2; const halfWidth = width / 2; @@ -142,7 +150,7 @@ function IsolatedRoofModel({ {pillars.map((p, i) => ( - + ))} @@ -157,21 +165,21 @@ function IsolatedRoofModel({ - + - + - + @@ -183,21 +191,21 @@ function IsolatedRoofModel({ - + - + - + @@ -208,7 +216,7 @@ function IsolatedRoofModel({ {/* Rótulo Superior */} diff --git a/app/src/components/three/Tower3D.tsx b/app/src/components/three/Tower3D.tsx index d69c011..d0e4f80 100644 --- a/app/src/components/three/Tower3D.tsx +++ b/app/src/components/three/Tower3D.tsx @@ -114,10 +114,16 @@ function buildTowerGeometry( return { nodes, members }; } -function pressureColor(phi: number, forceKN: number): THREE.Color { +import { useCanvasTheme } from '@/lib/theme'; + +function pressureColor(phi: number, forceKN: number, isDark: boolean): THREE.Color { const intensity = Math.min(1, (phi * forceKN) / 30); const hue = 220 - intensity * 220; - return new THREE.Color(`hsl(${hue}, ${60 + intensity * 30}%, ${50 - intensity * 10}%)`); + // Ajusta a luminosidade no HSL para contrastar melhor em fundos escuros + const lightness = isDark + ? (60 + intensity * 10) + : (50 - intensity * 10); + return new THREE.Color(`hsl(${hue}, ${60 + intensity * 30}%, ${lightness}%)`); } function TowerModel({ @@ -130,13 +136,16 @@ function TowerModel({ alphaWind, forceKN, }: Tower3DInput) { + const theme = useCanvasTheme(); + const isDark = theme === 'dark'; + const geometry = useMemo( () => buildTowerGeometry(section, panels, baseWidth, height), [section, panels, baseWidth, height], ); const barRadius = barType === 'circular' ? 0.04 : 0.03; - const barColor = pressureColor(phi, forceKN); + const barColor = pressureColor(phi, forceKN, isDark); // Direção do vetor de força const alphaRad = (alphaWind * Math.PI) / 180; @@ -150,14 +159,14 @@ function TowerModel({ {/* Solo */} - + {/* Nós (esferas pequenas) */} {geometry.nodes.map((node, idx) => ( - + ))} @@ -178,9 +187,9 @@ function TowerModel({ const color = m.type === 'leg' - ? '#1e293b' + ? (isDark ? '#f1f5f9' : '#1e293b') : m.type === 'horizontal' - ? '#64748b' + ? (isDark ? '#cbd5e1' : '#64748b') : barColor; return ( @@ -205,7 +214,7 @@ function TowerModel({ @@ -216,6 +225,8 @@ function TowerModel({ } export default function Tower3DViewer(input: Tower3DInput) { + const theme = useCanvasTheme(); + const isDark = theme === 'dark'; const { baseWidth, height } = input; const dist = Math.max(baseWidth * 3, height * 1.2); @@ -236,7 +247,13 @@ export default function Tower3DViewer(input: Tower3DInput) { - + diff --git a/app/src/lib/theme.tsx b/app/src/lib/theme.tsx index 539490f..5573c8a 100644 --- a/app/src/lib/theme.tsx +++ b/app/src/lib/theme.tsx @@ -61,4 +61,24 @@ export function useTheme(): ThemeContextValue { const ctx = useContext(ThemeContext); if (!ctx) throw new Error('useTheme deve ser usado dentro de ThemeProvider'); return ctx; +} + +export function useCanvasTheme(): 'light' | 'dark' { + const [isDark, setIsDark] = useState(() => { + if (typeof document === 'undefined') return false; + return document.documentElement.classList.contains('dark'); + }); + + useEffect(() => { + const observer = new MutationObserver(() => { + setIsDark(document.documentElement.classList.contains('dark')); + }); + observer.observe(document.documentElement, { + attributes: true, + attributeFilter: ['class'], + }); + return () => observer.disconnect(); + }, []); + + return isDark ? 'dark' : 'light'; } \ No newline at end of file diff --git a/app/src/pages/IsolatedRoofModule.tsx b/app/src/pages/IsolatedRoofModule.tsx index 8ac3137..5cd8c99 100644 --- a/app/src/pages/IsolatedRoofModule.tsx +++ b/app/src/pages/IsolatedRoofModule.tsx @@ -162,8 +162,8 @@ const IsolatedRoofModule: React.FC = () => { {/* Coluna Central: 3D */}
- θ = {theta}° - {type === 'shed' ? 'Uma água' : 'Duas águas'} + θ = {theta}° + {type === 'shed' ? 'Uma água' : 'Duas águas'}