Files
BrainWind/app/src/components/EducationalManual.tsx
T

217 lines
10 KiB
TypeScript

import React from 'react';
import { HelpCircle, Info, Settings2 } from 'lucide-react';
import { Button } from '@/components/ui/button';
import {
Sheet,
SheetContent,
SheetDescription,
SheetHeader,
SheetTitle,
SheetTrigger,
} from '@/components/ui/sheet';
import { manuals } from '@/data/manuals';
import { WindFlowGrid2D } from './WindFlowGrid2D';
interface EducationalManualProps {
type: string;
params: Record<string, any>;
}
export function EducationalManual({ type, params }: EducationalManualProps) {
const manual = manuals[type];
if (!manual) {
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>
<Button
variant="outline"
size="icon"
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"
>
<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">
<SheetHeader className="border-b border-border pb-4 flex flex-col gap-1.5">
<div className="flex items-center gap-2 text-primary">
<HelpCircle className="size-5" />
<SheetTitle className="text-xl font-bold tracking-tight">{manual.title}</SheetTitle>
</div>
<SheetDescription className="text-sm text-muted-foreground leading-relaxed">
{manual.intro}
</SheetDescription>
</SheetHeader>
{/* 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) => (
<div key={idx} className="flex flex-col gap-3 bg-muted/20 p-4 rounded-xl border border-border/40">
<h3 className="text-base font-bold text-primary flex items-center gap-2 border-b border-border/60 pb-1.5">
{section.title}
</h3>
<div className="text-sm prose prose-neutral dark:prose-invert max-w-none text-muted-foreground">
{section.content}
</div>
</div>
))}
</div>
<div className="mt-auto border-t border-border pt-4 text-center">
<p className="text-[10px] text-muted-foreground font-mono">
BrainWind v1.0 Referência: ABNT NBR 6123:2023
</p>
</div>
</SheetContent>
</Sheet>
);
}