fix(preventivo): slide deck 100vh — nessuno scroll di pagina

- ProposalDeck: outer div h-screen overflow-hidden, content wrapper h-full
- Rimosso il div interno ridondante min-h-screen
- useEffect blocca body overflow mentre la deck è aperta
- Tutti i 20 componenti slide: min-h-screen → h-full

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-20 18:08:40 +02:00
parent fdcc938252
commit c803efe059
21 changed files with 42 additions and 39 deletions
@@ -129,10 +129,14 @@ export function ProposalDeck({ proposal, onAccept, onReject }: Props) {
return () => window.removeEventListener("keydown", handler); return () => window.removeEventListener("keydown", handler);
}, [next, prev]); }, [next, prev]);
// Blocca lo scroll del body mentre la deck è visibile
useEffect(() => {
document.body.style.overflow = "hidden";
return () => { document.body.style.overflow = ""; };
}, []);
return ( return (
<div className="relative min-h-screen bg-white font-sans select-none"> <div className="relative h-screen overflow-hidden bg-white font-sans select-none">
{/* Slide corrente */}
<div className="min-h-screen flex flex-col">
{/* Topbar */} {/* Topbar */}
<div className="fixed top-0 left-0 right-0 z-20 flex items-center justify-between px-8 py-4 bg-white/90 backdrop-blur-sm border-b border-border"> <div className="fixed top-0 left-0 right-0 z-20 flex items-center justify-between px-8 py-4 bg-white/90 backdrop-blur-sm border-b border-border">
<span className="text-xs font-mono text-muted-foreground tracking-widest uppercase"> <span className="text-xs font-mono text-muted-foreground tracking-widest uppercase">
@@ -143,8 +147,8 @@ export function ProposalDeck({ proposal, onAccept, onReject }: Props) {
</span> </span>
</div> </div>
{/* Contenuto slide */} {/* Contenuto slide — riempie esattamente lo spazio tra le due barre fisse */}
<div className="flex-1 pt-16 pb-20"> <div className="h-full pt-16 pb-20 overflow-hidden">
{slides[current].component} {slides[current].component}
</div> </div>
@@ -188,6 +192,5 @@ export function ProposalDeck({ proposal, onAccept, onReject }: Props) {
</div> </div>
</div> </div>
</div> </div>
</div>
); );
} }
@@ -44,7 +44,7 @@ export function AcceptSection({ slug, tiers, header, onAccept, onReject }: Props
} }
return ( return (
<div className="min-h-screen flex flex-col justify-center px-16 py-24 space-y-10"> <div className="h-full flex flex-col justify-center px-16 py-24 space-y-10">
<div> <div>
<p className="text-xs font-mono tracking-widest text-muted-foreground uppercase"> <p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">
Accettazione formale Accettazione formale
@@ -2,7 +2,7 @@ type Props = { number: string; title: string; subtitle: string };
export function ChapterDivider({ number, title, subtitle }: Props) { export function ChapterDivider({ number, title, subtitle }: Props) {
return ( return (
<div className="min-h-screen flex flex-col justify-center px-16 py-24 space-y-6"> <div className="h-full flex flex-col justify-center px-16 py-24 space-y-6">
<p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">Capitolo</p> <p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">Capitolo</p>
<div className="space-y-2"> <div className="space-y-2">
<p className="text-8xl font-light text-primary">{number}</p> <p className="text-8xl font-light text-primary">{number}</p>
@@ -11,7 +11,7 @@ type Props = {
export function ClosingSection({ consultant, header, state, selectedTier, acceptedAt }: Props) { export function ClosingSection({ consultant, header, state, selectedTier, acceptedAt }: Props) {
return ( return (
<div className="min-h-screen flex flex-col justify-between px-16 py-24"> <div className="h-full flex flex-col justify-between px-16 py-24">
<p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">Come si parte</p> <p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">Come si parte</p>
<div className="space-y-6"> <div className="space-y-6">
@@ -10,7 +10,7 @@ export function ComparisonMatrixSection({ matrix, tiers }: Props) {
const tierLetters = tiers.map((t) => t.tierLetter); const tierLetters = tiers.map((t) => t.tierLetter);
return ( return (
<div className="min-h-screen flex flex-col justify-center px-16 py-24 space-y-8"> <div className="h-full flex flex-col justify-center px-16 py-24 space-y-8">
<div> <div>
<p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">Riepilogo del lavoro</p> <p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">Riepilogo del lavoro</p>
<h2 className="text-5xl font-light text-foreground mt-4"> <h2 className="text-5xl font-light text-foreground mt-4">
@@ -4,7 +4,7 @@ type Props = { header: AssembledProposal["header"] };
export function CoverSection({ header }: Props) { export function CoverSection({ header }: Props) {
return ( return (
<div className="min-h-screen flex flex-col justify-between px-16 py-24"> <div className="h-full flex flex-col justify-between px-16 py-24">
<p className="text-xs font-mono tracking-widest text-muted-foreground uppercase"> <p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">
Documento di Soluzione Documento di Soluzione
</p> </p>
@@ -5,7 +5,7 @@ type Props = { deliverables: ProposalContent["deliverables"] };
export function DeliverablesSection({ deliverables }: Props) { export function DeliverablesSection({ deliverables }: Props) {
return ( return (
<div className="min-h-screen flex items-center px-16 py-24"> <div className="h-full flex items-center px-16 py-24">
<div className="grid grid-cols-2 gap-8 w-full"> <div className="grid grid-cols-2 gap-8 w-full">
{/* Deliverable */} {/* Deliverable */}
<div className="border border-primary/20 bg-primary/5 rounded-xl p-8 space-y-4"> <div className="border border-primary/20 bg-primary/5 rounded-xl p-8 space-y-4">
@@ -4,7 +4,7 @@ type Props = { consultant: ConsultantProfile };
export function FactsSection({ consultant }: Props) { export function FactsSection({ consultant }: Props) {
return ( return (
<div className="min-h-screen flex flex-col justify-center px-16 py-24 space-y-12"> <div className="h-full flex flex-col justify-center px-16 py-24 space-y-12">
<div> <div>
<p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">Tre fatti</p> <p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">Tre fatti</p>
<h2 className="text-5xl font-light text-foreground mt-4"> <h2 className="text-5xl font-light text-foreground mt-4">
@@ -8,7 +8,7 @@ const CHAPTERS = [
export function IndexSection() { export function IndexSection() {
return ( return (
<div className="min-h-screen flex flex-col justify-center px-16 py-24 space-y-8"> <div className="h-full flex flex-col justify-center px-16 py-24 space-y-8">
<p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">Sommario</p> <p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">Sommario</p>
<h2 className="text-5xl font-light text-foreground"> <h2 className="text-5xl font-light text-foreground">
Cinque <span className="text-primary">capitoli.</span> Cinque <span className="text-primary">capitoli.</span>
@@ -12,7 +12,7 @@ export function NextStepsSection({ consultant, header }: Props) {
const expiryNote = `Valida ${header.validityDays} giorni dalla data di invio.`; const expiryNote = `Valida ${header.validityDays} giorni dalla data di invio.`;
return ( return (
<div className="min-h-screen flex flex-col justify-center px-16 py-24 space-y-10"> <div className="h-full flex flex-col justify-center px-16 py-24 space-y-10">
<div> <div>
<p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">Come procedere ora</p> <p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">Come procedere ora</p>
<h2 className="text-5xl font-light text-foreground mt-4"> <h2 className="text-5xl font-light text-foreground mt-4">
@@ -10,7 +10,7 @@ function formatEur(val: string | null | undefined): string {
export function PricingSection({ tiers }: Props) { export function PricingSection({ tiers }: Props) {
return ( return (
<div className="min-h-screen flex flex-col justify-center px-16 py-24 space-y-10"> <div className="h-full flex flex-col justify-center px-16 py-24 space-y-10">
<div> <div>
<p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">Le tre opzioni</p> <p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">Le tre opzioni</p>
<h2 className="text-5xl font-light text-foreground mt-4"> <h2 className="text-5xl font-light text-foreground mt-4">
@@ -4,7 +4,7 @@ type Props = { problem: ProblemNode };
export function ProblemNodeSection({ problem }: Props) { export function ProblemNodeSection({ problem }: Props) {
return ( return (
<div className="min-h-screen flex flex-col justify-center px-16 py-24 space-y-8 max-w-4xl"> <div className="h-full flex flex-col justify-center px-16 py-24 space-y-8 max-w-4xl">
<div> <div>
<p className="text-xs font-mono tracking-widest text-destructive uppercase"> <p className="text-xs font-mono tracking-widest text-destructive uppercase">
Problema {problem.id} · {problem.subtitle} Problema {problem.id} · {problem.subtitle}
@@ -5,7 +5,7 @@ type Props = { scope: ProposalContent["scope"] };
export function ScopeSection({ scope }: Props) { export function ScopeSection({ scope }: Props) {
return ( return (
<div className="min-h-screen flex items-center px-16 py-24"> <div className="h-full flex items-center px-16 py-24">
<div className="grid grid-cols-2 gap-12 w-full"> <div className="grid grid-cols-2 gap-12 w-full">
{/* Scope */} {/* Scope */}
<div className="border border-primary/20 bg-primary/5 rounded-xl p-8 space-y-4"> <div className="border border-primary/20 bg-primary/5 rounded-xl p-8 space-y-4">
@@ -4,7 +4,7 @@ type Props = { solution: SolutionNode };
export function SolutionNodeSection({ solution }: Props) { export function SolutionNodeSection({ solution }: Props) {
return ( return (
<div className="min-h-screen flex flex-col justify-center px-16 py-24 space-y-8 max-w-4xl"> <div className="h-full flex flex-col justify-center px-16 py-24 space-y-8 max-w-4xl">
<div> <div>
<p className="text-xs font-mono tracking-widest text-primary uppercase"> <p className="text-xs font-mono tracking-widest text-primary uppercase">
{solution.subtitle} {solution.subtitle}
@@ -4,7 +4,7 @@ type Props = { synthesis: ProposalContent["solutionSynthesis"] };
export function SolutionSynthesisSection({ synthesis }: Props) { export function SolutionSynthesisSection({ synthesis }: Props) {
return ( return (
<div className="min-h-screen flex flex-col justify-center px-16 py-24 space-y-10"> <div className="h-full flex flex-col justify-center px-16 py-24 space-y-10">
<div> <div>
<p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">Sintesi della soluzione</p> <p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">Sintesi della soluzione</p>
<h2 className="text-5xl font-light text-foreground mt-4"> <h2 className="text-5xl font-light text-foreground mt-4">
@@ -4,7 +4,7 @@ type Props = { stages: ProposalContent["stagesRecap"]["stages"] };
export function StagesRecapSection({ stages }: Props) { export function StagesRecapSection({ stages }: Props) {
return ( return (
<div className="min-h-screen flex flex-col justify-center px-16 py-24 space-y-10"> <div className="h-full flex flex-col justify-center px-16 py-24 space-y-10">
<div> <div>
<p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">Recap del progresso</p> <p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">Recap del progresso</p>
<h2 className="text-5xl font-light text-foreground mt-4"> <h2 className="text-5xl font-light text-foreground mt-4">
@@ -5,7 +5,7 @@ type Props = { consultant: ConsultantProfile };
export function StrategistSection({ consultant }: Props) { export function StrategistSection({ consultant }: Props) {
return ( return (
<div className="min-h-screen flex items-center px-16 py-24"> <div className="h-full flex items-center px-16 py-24">
<div className="grid grid-cols-3 gap-12 w-full"> <div className="grid grid-cols-3 gap-12 w-full">
{/* Foto */} {/* Foto */}
<div className="flex flex-col items-center justify-center"> <div className="flex flex-col items-center justify-center">
@@ -7,7 +7,7 @@ type Props = {
export function SynthesisDiagramSection({ synthesis }: Props) { export function SynthesisDiagramSection({ synthesis }: Props) {
return ( return (
<div className="min-h-screen flex flex-col justify-center px-16 py-24 space-y-10"> <div className="h-full flex flex-col justify-center px-16 py-24 space-y-10">
<div> <div>
<p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">Sintesi del problema</p> <p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">Sintesi del problema</p>
<h2 className="text-5xl font-light text-foreground mt-4"> <h2 className="text-5xl font-light text-foreground mt-4">
@@ -11,7 +11,7 @@ export function TestimonialsSection({ testimonials, page, totalPages }: Props) {
const slice = testimonials.slice((page - 1) * perPage, page * perPage); const slice = testimonials.slice((page - 1) * perPage, page * perPage);
return ( return (
<div className="min-h-screen flex flex-col px-16 py-24 space-y-8"> <div className="h-full flex flex-col px-16 py-24 space-y-8">
<div> <div>
<p className="text-xs font-mono tracking-widest text-muted-foreground uppercase"> <p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">
Pagina {page} di {totalPages} · Cosa dicono di me Pagina {page} di {totalPages} · Cosa dicono di me
@@ -12,7 +12,7 @@ export function TimelineSection({ timeline }: Props) {
const weeks = Array.from({ length: timeline.totalWeeks }, (_, i) => i + 1); const weeks = Array.from({ length: timeline.totalWeeks }, (_, i) => i + 1);
return ( return (
<div className="min-h-screen flex flex-col justify-center px-16 py-24 space-y-10"> <div className="h-full flex flex-col justify-center px-16 py-24 space-y-10">
<div> <div>
<p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">Timeline</p> <p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">Timeline</p>
<h2 className="text-5xl font-light text-foreground mt-4"> <h2 className="text-5xl font-light text-foreground mt-4">
@@ -11,7 +11,7 @@ export function VisionSection({ vision, header }: Props) {
const mid = Math.floor(words.length / 2); const mid = Math.floor(words.length / 2);
return ( return (
<div className="min-h-screen flex flex-col justify-center px-16 py-24 space-y-8"> <div className="h-full flex flex-col justify-center px-16 py-24 space-y-8">
<p className="text-xs font-mono tracking-widest text-muted-foreground uppercase"> <p className="text-xs font-mono tracking-widest text-muted-foreground uppercase">
Dove andiamo Dove andiamo
</p> </p>