melhora visualizacao movel

This commit is contained in:
Rodrigo Bertoldo de Sousa Martins committed 2026-09-11 14:30:23 -03:00
1 parent 63d5cbebe7
commit 7994e56cd0
3 files changed
+80 -48

No files matched your search

+25 -8
View File
@@ -1,7 +1,17 @@
import { useAtlasStore } from "../store/useAtlasStore.js";
import type { Structure } from "../lib/api.js";
export function StructureInfoPanel({ bySlug }: { bySlug: Map<string, Structure> }) {
export function StructureInfoPanel({
bySlug,
onClose,
}: {
bySlug: Map<string, Structure>;
// No desktop o painel é uma gaveta lateral sempre visível (não faz
// sentido "fechar", só trocar de estrutura), então esse botão só existe
// quando a página que usa o painel passa um onClose — hoje é o caso da
// bottom sheet do Atlas no mobile.
onClose?: () => void;
}) {
const selectedStructureId = useAtlasStore((s) => s.selectedStructureId);
const selectStructure = useAtlasStore((s) => s.selectStructure);
@@ -17,17 +27,22 @@ export function StructureInfoPanel({ bySlug }: { bySlug: Map<string, Structure>
);
}
function handleClose() {
selectStructure(null);
onClose?.();
}
return (
<div className="space-y-3">
<div className="flex items-start justify-between">
<div>
<h2 className="text-lg font-semibold text-white">{structure.namePt}</h2>
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<h2 className="text-lg font-semibold text-white leading-snug">{structure.namePt}</h2>
<p className="text-sm text-slate-400 italic">{structure.nameEn}</p>
</div>
<button
onClick={() => selectStructure(null)}
className="text-slate-400 hover:text-white text-sm"
aria-label="Fechar"
onClick={handleClose}
className="shrink-0 text-slate-400 hover:text-white text-lg leading-none p-1 -m-1"
aria-label="Fechar detalhes"
>
✕
</button>
@@ -40,7 +55,9 @@ export function StructureInfoPanel({ bySlug }: { bySlug: Map<string, Structure>
{structure.system.namePt}
</span>
{structure.description && <p className="text-sm text-slate-300">{structure.description}</p>}
{structure.description && (
<p className="text-sm text-slate-300 leading-relaxed">{structure.description}</p>
)}
{structure.regionPath.length > 0 && (
<p className="text-xs text-slate-500">{structure.regionPath.join(" › ")}</p>
+29 -23
View File
@@ -57,13 +57,14 @@ export default function AtlasPage() {
</div>
</aside>
{(leftOpen || rightOpen) && (
{/* No mobile o painel de detalhes é uma bottom sheet (ver <aside> mais
abaixo) — o fundo escurecido só faz sentido pro drawer de camadas,
que ainda cobre a tela toda; a sheet já deixa o modelo 3D visível
por cima dela, então não precisa (e não deveria) escurecer a cena. */}
{leftOpen && (
<div
className="fixed inset-0 bg-black/50 z-20 md:hidden"
onClick={() => {
setLeftOpen(false);
setRightOpen(false);
}}
onClick={() => setLeftOpen(false)}
/>
)}
@@ -78,28 +79,33 @@ export default function AtlasPage() {
>
☰ Camadas
</button>
<button
onClick={() => setRightOpen(true)}
className="md:hidden absolute top-3 right-3 z-10 bg-panel/90 border border-white/10 rounded-lg px-3 py-2 text-xs shadow-lg"
>
ℹ️ Detalhes
</button>
{!rightOpen && (
<button
onClick={() => setRightOpen(true)}
className="md:hidden absolute top-3 right-3 z-10 bg-panel/90 border border-white/10 rounded-lg px-3 py-2 text-xs shadow-lg"
>
ℹ️ Detalhes
</button>
)}
</div>
{/* Desktop: gaveta lateral fixa, igual à de camadas. Mobile: bottom
sheet que sobe de baixo pra cima e some — a parte anatômica
selecionada (destacada no modelo 3D, atrás dela) continua visível
por cima, em vez de ser tampada pela tela inteira do painel. */}
<aside
className={`fixed md:static inset-y-0 right-0 z-30 w-[86vw] max-w-[320px] md:w-auto
border-l border-white/10 bg-panel p-4 overflow-y-auto
transition-transform duration-200 md:translate-x-0
${rightOpen ? "translate-x-0" : "translate-x-full"}`}
className={`fixed md:static inset-x-0 bottom-0 md:inset-auto z-30
max-h-[65vh] md:max-h-none md:h-full w-full md:w-auto
border-t md:border-t-0 md:border-l border-white/10 bg-panel
rounded-t-2xl md:rounded-none p-4 pt-2 md:pt-4 overflow-y-auto
shadow-[0_-8px_24px_rgba(0,0,0,0.4)] md:shadow-none
transition-transform duration-200 md:!translate-y-0
${rightOpen ? "translate-y-0" : "translate-y-full"}`}
>
<button
onClick={() => setRightOpen(false)}
className="md:hidden text-slate-400 hover:text-white text-sm mb-2 px-2 py-1"
aria-label="Fechar painel"
>
✕ Fechar
</button>
<StructureInfoPanel bySlug={bySlug} />
{/* Alça de arrastar — só decorativa, mas é o sinal visual padrão de
bottom sheet ("puxe/deslize pra baixo pra fechar"). */}
<div className="md:hidden mx-auto mb-2 h-1.5 w-10 rounded-full bg-white/15" />
<StructureInfoPanel bySlug={bySlug} onClose={() => setRightOpen(false)} />
</aside>
</div>
);
+26 -17
View File
@@ -112,13 +112,13 @@ export default function PhysicalExamPage() {
</p>
</aside>
{(leftOpen || rightOpen) && (
{/* Só o drawer de camadas/técnicas (esquerda) cobre a tela toda no
mobile — o painel de detalhes virou uma bottom sheet (ver <aside>
mais abaixo) que já deixa o corpo 3D visível por cima dela. */}
{leftOpen && (
<div
className="fixed inset-0 bg-black/50 z-20 md:hidden"
onClick={() => {
setLeftOpen(false);
setRightOpen(false);
}}
onClick={() => setLeftOpen(false)}
/>
)}
@@ -146,26 +146,35 @@ export default function PhysicalExamPage() {
>
☰ Técnicas
</button>
<button
onClick={() => setRightOpen(true)}
className="md:hidden absolute top-3 right-3 z-10 bg-panel/90 border border-white/10 rounded-lg px-3 py-2 text-xs shadow-lg"
>
ℹ️ Detalhes
</button>
{!rightOpen && (
<button
onClick={() => setRightOpen(true)}
className="md:hidden absolute top-3 right-3 z-10 bg-panel/90 border border-white/10 rounded-lg px-3 py-2 text-xs shadow-lg"
>
ℹ️ Detalhes
</button>
)}
</div>
{/* Desktop: gaveta lateral fixa. Mobile: bottom sheet (sobe de baixo
pra cima, altura limitada ao conteúdo) — o ponto de exame
selecionado continua visível no corpo 3D acima dela. */}
<aside
className={`fixed md:static inset-y-0 right-0 z-30 w-[86vw] max-w-[320px] md:w-auto
border-l border-white/10 bg-panel p-4 overflow-y-auto space-y-3
transition-transform duration-200 md:translate-x-0
${rightOpen ? "translate-x-0" : "translate-x-full"}`}
className={`fixed md:static inset-x-0 bottom-0 md:inset-auto z-30
max-h-[65vh] md:max-h-none md:h-full w-full md:w-auto
border-t md:border-t-0 md:border-l border-white/10 bg-panel
rounded-t-2xl md:rounded-none p-4 pt-2 md:pt-4 overflow-y-auto space-y-3
shadow-[0_-8px_24px_rgba(0,0,0,0.4)] md:shadow-none
transition-transform duration-200 md:!translate-y-0
${rightOpen ? "translate-y-0" : "translate-y-full"}`}
>
<div className="md:hidden mx-auto h-1.5 w-10 rounded-full bg-white/15" />
<button
onClick={() => setRightOpen(false)}
className="md:hidden text-slate-400 hover:text-white text-sm mb-2 px-2 py-1"
className="md:hidden absolute top-2 right-3 text-slate-400 hover:text-white text-lg leading-none p-1"
aria-label="Fechar painel"
>
✕ Fechar
✕
</button>
{!selected ? (