feat: aprimoramento didatico dos SVGs, rotulagem de vistas, legendas e explicacao contextualizada

This commit is contained in:
2026-07-10 00:05:29 +00:00
parent 40e73e734a
commit 59ac5c1827
5 changed files with 673 additions and 276 deletions
+144 -2
View File
@@ -1,4 +1,5 @@
import { BookOpen, HelpCircle } from 'lucide-react';
import React from 'react';
import { HelpCircle, Info, Settings2 } from 'lucide-react';
import { Button } from '@/components/ui/button';
import {
Sheet,
@@ -23,6 +24,144 @@ export function EducationalManual({ type, params }: EducationalManualProps) {
return null;
}
// Gera explicações interpretativas dinâmicas com base nas opções selecionadas no painel
const renderConfigurationExplanation = () => {
const explanations: React.ReactNode[] = [];
// --- Abóbadas (vault) ---
if (type === 'vault') {
const regime = params.regime || 'laminar-rough';
const cpi = Number(params.localCpi || 0);
// Regime de escoamento
if (regime === 'laminar-rough') {
explanations.push(
<div key="vault-regime" className="text-xs border-l-2 border-sky-400 pl-3 py-1 space-y-1">
<span className="font-bold text-foreground block">Escoamento: Baixa Turbulência (Tabelas 15-17)</span>
<p>Representa vento uniforme sobre terreno desobstruído. O escoamento flui de forma limpa sobre o arco, gerando os valores tradicionais de sucção no topo.</p>
</div>
);
} else {
explanations.push(
<div key="vault-regime" className="text-xs border-l-2 border-red-500 pl-3 py-1 space-y-1">
<span className="font-bold text-foreground block">Escoamento: Regime Turbulento (Tabelas 18-20)</span>
<p>O vento apresenta alta turbulência devido a obstáculos no terreno. As correntes de vento ondulantes (exibidas no simulador) induzem picos de pressões dinâmicas flutuantes.</p>
</div>
);
}
// Permeabilidade (Cpi)
if (cpi === 0) {
explanations.push(
<div key="vault-cpi" className="text-xs border-l-2 border-slate-400 pl-3 py-1 space-y-1">
<span className="font-bold text-foreground block">Pressão Interna Neutralizada (Cpi = 0.0)</span>
<p>As aberturas são inexistentes ou estão distribuídas igualmente nas faces. A força resultante no arco depende exclusivamente da sucção externa.</p>
</div>
);
} else if (cpi > 0) {
explanations.push(
<div key="vault-cpi" className="text-xs border-l-2 border-orange-500 pl-3 py-1 space-y-1">
<span className="font-bold text-orange-500 block">Abóbada Inflada (Cpi = +{cpi})</span>
<p>Uma abertura dominante na face de barlavento permite a entrada do ar, "inflando" a abóbada de dentro para fora (indicado pelas setas laranjas). Essa pressão interna empurra a cobertura para cima, somando-se à sucção externa do vento e aumentando de forma crítica a força de arrancamento do telhado!</p>
</div>
);
} else {
explanations.push(
<div key="vault-cpi" className="text-xs border-l-2 border-blue-500 pl-3 py-1 space-y-1">
<span className="font-bold text-blue-500 block">Abóbada Sugada / Vácuo (Cpi = {cpi})</span>
<p>Com aberturas dominantes nas faces protegidas (laterais ou sotavento), o ar interno é sugado para fora, criando um vácuo interno (setas azuis). Esse efeito de vácuo ajuda a compensar e aliviar a sucção externa no topo, mas puxa as paredes para dentro.</p>
</div>
);
}
}
// --- Cilindros (cylinder) ---
if (type === 'cylinder') {
const isSmooth = params.surface === 'smooth';
const cpi = Number(params.cpi || 0);
explanations.push(
<div key="cyl-surface" className="text-xs border-l-2 border-sky-400 pl-3 py-1 space-y-1">
<span className="font-bold text-foreground block">Superfície: {isSmooth ? 'Lisa' : 'Rugosa'}</span>
<p>{isSmooth
? 'Superfície de baixo atrito. No regime supercrítico, o descolamento da camada limite é atrasado significativamente, fazendo o coeficiente de arrasto Ca cair para valores muito baixos (~0.4).'
: 'Casca áspera. A rugosidade gera microturbulências na superfície do cilindro que impedem a esteira de estreitar excessivamente, mantendo o arrasto Ca em níveis elevados no regime crítico/supercrítico.'
}</p>
</div>
);
if (cpi > 0) {
explanations.push(
<div key="cyl-cpi" className="text-xs border-l-2 border-orange-500 pl-3 py-1 space-y-1">
<span className="font-bold text-orange-500 block">Reservatório Inflado (Cpi positivo)</span>
<p>O ar interno pressiona as paredes do silo/chaminé de dentro para fora, somando-se às sucções externas nas laterais.</p>
</div>
);
}
}
// --- Muros e Placas (sign) ---
if (type === 'sign') {
const hasEndPlates = params.hasEndPlates === true;
const alpha = Number(params.alpha || 90);
explanations.push(
<div key="sign-alpha" className="text-xs border-l-2 border-sky-400 pl-3 py-1 space-y-1">
<span className="font-bold text-foreground block">Incidência do Vento: {alpha}º</span>
<p>{alpha === 90
? 'Vento Perpendicular: o arrasto atua uniformemente, concentrando a força resultante exatamente no centro da placa (sem torque de torção nas fundações).'
: 'Vento Oblíquo: o fluxo se concentra na borda esquerda de ataque. Isso gera uma excentricidade horizontal na força (e = 0.25 L), introduzindo um momento torsor crítico que deve ser suportado pelos pilares.'
}</p>
</div>
);
explanations.push(
<div key="sign-plates" className="text-xs border-l-2 border-red-500 pl-3 py-1 space-y-1">
<span className="font-bold text-foreground block">Abas Laterais (End Plates): {hasEndPlates ? 'Com abas' : 'Sem abas'}</span>
<p>{hasEndPlates
? 'As abas vermelhas mostradas no simulador impedem o ar de escapar pelas laterais do muro, gerando um escoamento bidimensional plano que eleva a força de arrasto Cf ao máximo.'
: 'O vento escoa tridimensionalmente pelas bordas laterais livres, criando um efeito de alívio aerodinâmico que reduz a força resultante nas pontas do muro.'
}</p>
</div>
);
}
// --- Galpões (warehouse) ---
if (type === 'warehouse') {
const cpi = Number(params.cpi || 0);
if (cpi > 0) {
explanations.push(
<div key="wh-cpi" className="text-xs border-l-2 border-orange-500 pl-3 py-1 space-y-1">
<span className="font-bold text-orange-500 block">Galpão Inflado (Cpi = +{cpi})</span>
<p>Ocorre quando aberturas dominantes na parede de barlavento (frente). O ar "sopra" para dentro e expande o galpão de dentro para fora, somando-se à sucção externa do telhado e aumentando de forma gravíssima o risco de arrancamento da cobertura!</p>
</div>
);
} else if (cpi < 0) {
explanations.push(
<div key="wh-cpi" className="text-xs border-l-2 border-blue-500 pl-3 py-1 space-y-1">
<span className="font-bold text-blue-500 block">Galpão Desinflado / Vácuo (Cpi = {cpi})</span>
<p>Ocorre com aberturas nas paredes laterais ou de trás (sotavento). O ar interno é sugado, puxando as chapas do telhado para dentro e ajudando a contrapor a sucção do vento externo.</p>
</div>
);
}
}
if (explanations.length === 0) return null;
return (
<div className="flex flex-col gap-3 bg-slate-900/10 p-4 border border-border/60 rounded-xl my-4">
<div className="flex items-center gap-2 text-primary border-b border-border/40 pb-1.5">
<Settings2 className="size-4" />
<h4 className="text-xs font-bold uppercase tracking-wider">Análise das Suas Configurações</h4>
</div>
<div className="flex flex-col gap-3">
{explanations}
</div>
</div>
);
};
return (
<Sheet>
<SheetTrigger asChild>
@@ -32,7 +171,7 @@ export function EducationalManual({ type, params }: EducationalManualProps) {
className="size-10 bg-background/80 backdrop-blur-xs border border-border shadow-md hover:bg-accent/80 transition-all rounded-full flex items-center justify-center"
title="Manual Didático da Norma NBR 6123"
>
<BookOpen className="size-5 text-primary animate-pulse" />
<Info className="size-5 text-primary animate-pulse" />
</Button>
</SheetTrigger>
<SheetContent className="overflow-y-auto w-full sm:max-w-xl p-6 flex flex-col gap-6 border-l border-border bg-card">
@@ -49,6 +188,9 @@ export function EducationalManual({ type, params }: EducationalManualProps) {
{/* Simulador Interativo 2D no topo do manual */}
<WindFlowGrid2D type={type} params={params} />
{/* Quadro Dinâmico explicativo dos seletores */}
{renderConfigurationExplanation()}
{/* Seções de Texto e Fórmulas */}
<div className="flex flex-col gap-6 text-foreground leading-relaxed">
{manual.sections.map((section, idx) => (