style: add complete light mode support to Visualizador 3D

This commit is contained in:
2026-09-21 00:38:40 +00:00
parent ff9ce261a0
commit 20056f5ddc
2 changed files with 34 additions and 34 deletions
+2 -2
View File
@@ -81,7 +81,7 @@ export const ModelViewer3D: React.FC<ModelViewer3DProps> = ({
// 1. Scene
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x0a0f1d);
scene.background = null; // Permite que o fundo da div (claro ou escuro) apareça
sceneRef.current = scene;
// 2. Cameras
@@ -538,7 +538,7 @@ export const ModelViewer3D: React.FC<ModelViewer3DProps> = ({
onPointerMove={handlePointerMove}
onPointerLeave={handlePointerLeave}
onDoubleClick={handleDoubleClick}
className="relative w-full h-full min-h-[600px] bg-slate-950 rounded-2xl overflow-hidden border border-slate-800 shadow-2xl select-none"
className="relative w-full h-full min-h-[600px] bg-slate-50 dark:bg-slate-950 rounded-2xl overflow-hidden border border-slate-200 dark:border-slate-800 shadow-xl dark:shadow-2xl select-none"
>
{/* Top Right: Interactive ViewCube */}
<div className="absolute top-4 right-4 z-20">
+32 -32
View File
@@ -464,7 +464,7 @@ export default function Visualizador3D() {
return (
<div className="flex flex-col h-[calc(100vh-4rem)] p-4 md:p-6 space-y-4 max-w-[1920px] mx-auto overflow-hidden">
{/* Top Header Bar */}
<div className="flex flex-wrap items-center justify-between gap-4 p-4 bg-slate-900/90 backdrop-blur-md border border-slate-800 rounded-2xl shadow-xl">
<div className="flex flex-wrap items-center justify-between gap-4 p-4 bg-white/90 dark:bg-slate-900/90 backdrop-blur-md border border-slate-200 dark:border-slate-800 rounded-2xl shadow-lg dark:shadow-xl">
{/* Left: Title, OF Selector & Phase Filter */}
<div className="flex flex-wrap items-center gap-4">
<div className="flex items-center gap-3">
@@ -472,21 +472,21 @@ export default function Visualizador3D() {
<Box className="w-6 h-6" />
</div>
<div>
<h1 className="text-xl font-bold text-white tracking-tight flex items-center gap-2">
<h1 className="text-xl font-bold text-slate-800 dark:text-white tracking-tight flex items-center gap-2">
Visualizador 3D Industrial
<span className="px-2 py-0.5 rounded-full text-[10px] font-mono font-bold bg-cyan-500/20 text-cyan-300 border border-cyan-500/40">
<span className="px-2 py-0.5 rounded-full text-[10px] font-mono font-bold bg-cyan-100 text-cyan-700 dark:bg-cyan-500/20 dark:text-cyan-300 border border-cyan-200 dark:border-cyan-500/40">
BIM + Produção
</span>
</h1>
<p className="text-xs text-slate-400">
<p className="text-xs text-slate-500 dark:text-slate-400">
Acompanhamento visual de peças, montagens e apontamentos industriais
</p>
</div>
</div>
{/* OF Selector Dropdown */}
<div className="flex items-center gap-2 bg-slate-950/80 px-3 py-1.5 rounded-xl border border-slate-800">
<span className="text-xs font-semibold text-slate-400">OF:</span>
<div className="flex items-center gap-2 bg-slate-50 dark:bg-slate-950/80 px-3 py-1.5 rounded-xl border border-slate-200 dark:border-slate-800">
<span className="text-xs font-semibold text-slate-500 dark:text-slate-400">OF:</span>
<select
value={selectedOF}
onChange={(e) => setSelectedOF(e.target.value)}
@@ -494,7 +494,7 @@ export default function Visualizador3D() {
>
<option value="" disabled className="text-slate-500">Selecione a OF...</option>
{ofs.map((ofItem) => (
<option key={ofItem.id} value={ofItem.of_number} className="bg-slate-900 text-white">
<option key={ofItem.id} value={ofItem.of_number} className="bg-white dark:bg-slate-900 text-slate-800 dark:text-white">
{ofItem.of_number} {ofItem.descritivo ? `— ${ofItem.descritivo}` : ''}
</option>
))}
@@ -524,13 +524,13 @@ export default function Visualizador3D() {
{/* Phase Filter Buttons */}
{phasesList.length > 0 && (
<div className="flex items-center gap-1 bg-slate-950/80 p-1 rounded-xl border border-slate-800">
<div className="flex items-center gap-1 bg-slate-50 dark:bg-slate-950/80 p-1 rounded-xl border border-slate-200 dark:border-slate-800">
<button
onClick={() => setSelectedPhase('all')}
className={`px-2.5 py-1 rounded-lg text-xs font-medium transition-all ${
selectedPhase === 'all'
? 'bg-cyan-500 text-slate-950 font-bold shadow-md shadow-cyan-500/30'
: 'text-slate-400 hover:text-slate-200'
? 'bg-cyan-500 text-white dark:text-slate-950 font-bold shadow-md shadow-cyan-500/30'
: 'text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-slate-200'
}`}
>
Todas Fases
@@ -541,8 +541,8 @@ export default function Visualizador3D() {
onClick={() => setSelectedPhase(f)}
className={`px-2.5 py-1 rounded-lg text-xs font-medium transition-all ${
selectedPhase === f
? 'bg-cyan-500 text-slate-950 font-bold shadow-md shadow-cyan-500/30'
: 'text-slate-400 hover:text-slate-200'
? 'bg-cyan-500 text-white dark:text-slate-950 font-bold shadow-md shadow-cyan-500/30'
: 'text-slate-600 dark:text-slate-400 hover:text-slate-900 dark:hover:text-slate-200'
}`}
>
Fase {f}
@@ -576,7 +576,7 @@ export default function Visualizador3D() {
<button
onClick={() => fileInputRef.current?.click()}
disabled={isLoadingModel}
className="flex items-center gap-2 px-4 py-2 bg-gradient-to-r from-cyan-500 to-blue-600 hover:from-cyan-400 hover:to-blue-500 text-slate-950 font-bold text-xs rounded-xl shadow-lg shadow-cyan-500/20 transition-all disabled:opacity-50 cursor-pointer"
className="flex items-center gap-2 px-4 py-2 bg-gradient-to-r from-cyan-500 to-blue-600 hover:from-cyan-400 hover:to-blue-500 text-white dark:text-slate-950 font-bold text-xs rounded-xl shadow-lg shadow-cyan-500/20 transition-all disabled:opacity-50 cursor-pointer"
>
{isLoadingModel ? (
<>
@@ -595,21 +595,21 @@ export default function Visualizador3D() {
{/* Production KPIs Bar */}
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
<div className="bg-slate-900/80 border border-slate-800 p-3 rounded-xl flex items-center justify-between">
<div className="bg-white/80 dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 p-3 rounded-xl flex items-center justify-between shadow-sm dark:shadow-none">
<div>
<span className="text-[10px] font-medium uppercase tracking-wider text-slate-400 block">
<span className="text-[10px] font-medium uppercase tracking-wider text-slate-500 dark:text-slate-400 block">
Total de Peças {activeMetrics.phaseLabel ? `(${activeMetrics.phaseLabel})` : ''}
</span>
<span className="text-lg font-mono font-extrabold text-white">
<span className="text-lg font-mono font-extrabold text-slate-800 dark:text-white">
{activeMetrics.totalPecas} peças
</span>
</div>
<Layers className="w-5 h-5 text-cyan-400" />
</div>
<div className="bg-slate-900/80 border border-slate-800 p-3 rounded-xl flex items-center justify-between">
<div className="bg-white/80 dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 p-3 rounded-xl flex items-center justify-between shadow-sm dark:shadow-none">
<div>
<span className="text-[10px] font-medium uppercase tracking-wider text-slate-400 block">
<span className="text-[10px] font-medium uppercase tracking-wider text-slate-500 dark:text-slate-400 block">
Apontamentos Realizados {activeMetrics.phaseLabel ? `(${activeMetrics.phaseLabel})` : ''}
</span>
<span className="text-lg font-mono font-extrabold text-emerald-400">
@@ -619,9 +619,9 @@ export default function Visualizador3D() {
<CheckCircle2 className="w-5 h-5 text-emerald-400" />
</div>
<div className="bg-slate-900/80 border border-slate-800 p-3 rounded-xl flex items-center justify-between">
<div className="bg-white/80 dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 p-3 rounded-xl flex items-center justify-between shadow-sm dark:shadow-none">
<div>
<span className="text-[10px] font-medium uppercase tracking-wider text-slate-400 block">
<span className="text-[10px] font-medium uppercase tracking-wider text-slate-500 dark:text-slate-400 block">
Evolução {activeMetrics.phaseLabel ? `(${activeMetrics.phaseLabel})` : 'da OF'}
</span>
<span className="text-lg font-mono font-extrabold text-amber-400">
@@ -631,9 +631,9 @@ export default function Visualizador3D() {
<TrendingUp className="w-5 h-5 text-amber-400" />
</div>
<div className="bg-slate-900/80 border border-slate-800 p-3 rounded-xl flex items-center justify-between">
<div className="bg-white/80 dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 p-3 rounded-xl flex items-center justify-between shadow-sm dark:shadow-none">
<div>
<span className="text-[10px] font-medium uppercase tracking-wider text-slate-400 block">
<span className="text-[10px] font-medium uppercase tracking-wider text-slate-500 dark:text-slate-400 block">
Peso {activeMetrics.phaseLabel ? `(${activeMetrics.phaseLabel})` : 'da Estrutura'}
</span>
<span className="text-lg font-mono font-extrabold text-cyan-300">
@@ -645,15 +645,15 @@ export default function Visualizador3D() {
</div>
{/* Main 3D Viewport */}
<div className="relative flex-1 w-full bg-slate-950 rounded-2xl overflow-hidden border border-slate-800 shadow-2xl">
<div className="relative flex-1 w-full bg-slate-50 dark:bg-slate-950 rounded-2xl overflow-hidden border border-slate-200 dark:border-slate-800 shadow-xl dark:shadow-2xl">
{isLoadingModel && (
<div className="absolute inset-0 z-30 flex flex-col items-center justify-center p-6 bg-slate-950/90 backdrop-blur-md text-white space-y-4">
<div className="p-4 bg-cyan-500/20 text-cyan-400 rounded-2xl border border-cyan-500/40 animate-pulse">
<div className="absolute inset-0 z-30 flex flex-col items-center justify-center p-6 bg-white/90 dark:bg-slate-950/90 backdrop-blur-md text-slate-800 dark:text-white space-y-4">
<div className="p-4 bg-cyan-100 text-cyan-600 dark:bg-cyan-500/20 dark:text-cyan-400 rounded-2xl border border-cyan-300 dark:border-cyan-500/40 animate-pulse">
<Loader2 className="w-10 h-10 animate-spin" />
</div>
<div className="text-center space-y-2 max-w-md">
<h3 className="text-lg font-bold text-white tracking-tight">{loadingStep}</h3>
<div className="w-full bg-slate-800 h-2 rounded-full overflow-hidden">
<h3 className="text-lg font-bold text-slate-800 dark:text-white tracking-tight">{loadingStep}</h3>
<div className="w-full bg-slate-200 dark:bg-slate-800 h-2 rounded-full overflow-hidden">
<div
className="bg-gradient-to-r from-cyan-500 to-blue-500 h-full transition-all duration-300"
style={{ width: `${loadingPercent}%` }}
@@ -665,14 +665,14 @@ export default function Visualizador3D() {
)}
{!modelData && !isLoadingModel && (
<div className="absolute inset-0 z-10 flex flex-col items-center justify-center p-6 text-center text-slate-400 space-y-4">
<div className="p-5 rounded-3xl bg-slate-900/80 border border-slate-800 shadow-2xl text-cyan-400">
<div className="absolute inset-0 z-10 flex flex-col items-center justify-center p-6 text-center text-slate-500 dark:text-slate-400 space-y-4">
<div className="p-5 rounded-3xl bg-white/80 dark:bg-slate-900/80 border border-slate-200 dark:border-slate-800 shadow-xl dark:shadow-2xl text-cyan-500 dark:text-cyan-400">
<Box className="w-16 h-16 stroke-[1.2]" />
</div>
<div className="space-y-1 max-w-md">
<h2 className="text-lg font-bold text-white">Nenhum modelo IFC carregado para {selectedOF}</h2>
<p className="text-xs text-slate-400 leading-relaxed">
Clique no botão <span className="text-cyan-300 font-semibold">"Carregar Modelo IFC"</span> acima para importar o arquivo de fabricação desta obra. Ele será gravado no banco de dados e recarregado automaticamente nas próximas visitas.
<h2 className="text-lg font-bold text-slate-800 dark:text-white">Nenhum modelo IFC carregado para {selectedOF}</h2>
<p className="text-xs text-slate-500 dark:text-slate-400 leading-relaxed">
Clique no botão <span className="text-cyan-600 dark:text-cyan-300 font-semibold">"Carregar Modelo IFC"</span> acima para importar o arquivo de fabricação desta obra. Ele será gravado no banco de dados e recarregado automaticamente nas próximas visitas.
</p>
</div>
</div>