Files
Investidor-V2/resources/js/components/investment-context-cards.tsx
T

176 lines
6.0 KiB
TypeScript

import { useState } from 'react';
import { ArrowRight } from 'lucide-react';
import {
HOME_SECTION,
HOME_SECTION_HEADING,
PORTAL_MORE_LINK,
} from '@/lib/portal-presentation';
const contexts = [
{
key: 'clusters',
href: '/clusters',
title: 'Clusters',
description: 'Cadeias de valor e lacunas produtivas.',
image: 'clusters-agroindustria',
alt: 'Triagem de produtos agrícolas numa unidade de transformação com área de cultivo ao fundo.',
},
{
key: 'corredores',
href: '/corredores',
title: 'Corredores',
description: 'Territórios, logística e conexões.',
image: 'corredores-logisticos-v2',
alt: 'Terminal de mercadorias junto à água, com contentores, uma grua e vias de acesso.',
},
{
key: 'projectos',
href: '/projectos-ancora',
title: 'Projectos âncora',
description: 'Projectos estruturantes e relações.',
image: 'projectos-ancora',
alt: 'Equipa de engenharia acompanha o planeamento de uma instalação de energia solar.',
},
{
key: 'educacao',
href: '/educacao',
title: 'Educação',
description: 'Investimentos em competências e formação.',
image: 'educacao-formacao',
alt: 'Jovens desenvolvem competências de electrónica e informática numa aula de formação técnica.',
},
{
key: 'documentos',
href: '/documentos',
title: 'Documentos e Formulários',
description:
'Legislação, procedimentos, formulários e materiais de apoio.',
image: 'documentos-formularios',
alt: 'Profissional analisa documentação empresarial organizada numa secretária de escritório.',
},
];
function ContextImage({
image,
alt,
preview,
}: {
image: string;
alt: string;
preview: boolean;
}) {
const [fallback, setFallback] = useState(0);
const base = `/images/investment-context/${image}`;
return (
<div className="aspect-video w-full shrink-0 overflow-hidden bg-slate-100">
{fallback < 2 ? (
<img
src={`${base}${fallback ? '-fallback' : ''}.webp`}
srcSet={
fallback
? undefined
: `${base}-480.webp 480w, ${base}.webp 960w`
}
sizes={
preview
? '(min-width: 1152px) 266px, (min-width: 1024px) 25vw, (min-width: 640px) 50vw, 100vw'
: '(min-width: 1152px) 357px, (min-width: 1024px) 33vw, (min-width: 640px) 50vw, 100vw'
}
alt={alt}
width={960}
height={540}
loading="lazy"
decoding="async"
className="h-full w-full object-cover object-center"
onError={() =>
setFallback((current) => Math.min(current + 1, 2))
}
/>
) : (
<span
role="img"
aria-label={alt}
className="flex h-full items-center justify-center px-5 text-center text-sm text-slate-600"
>
Imagem indisponível
</span>
)}
</div>
);
}
export function InvestmentContextGrid({
preview = false,
}: {
preview?: boolean;
}) {
const visibleContexts = preview ? contexts.slice(0, 4) : contexts;
return (
<nav
aria-label="Contextos de investimento"
className={
preview
? 'grid gap-4 sm:grid-cols-2 lg:grid-cols-4'
: 'grid gap-5 sm:grid-cols-2 lg:grid-cols-3'
}
>
{visibleContexts.map((context) => (
<a
key={context.key}
href={context.href}
aria-labelledby={`context-${context.key}-title`}
aria-describedby={`context-${context.key}-description`}
className="flex h-full min-w-0 flex-col overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm transition-colors hover:border-blue-700 focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-blue-700"
>
<ContextImage
image={context.image}
alt={context.alt}
preview={preview}
/>
<div className="flex flex-1 flex-col gap-1.5 p-4">
<h3
id={`context-${context.key}-title`}
className="text-lg leading-6 font-bold text-slate-900"
>
{context.title}
</h3>
<p
id={`context-${context.key}-description`}
className="text-sm leading-5 text-slate-600"
>
{context.description}
</p>
</div>
</a>
))}
</nav>
);
}
export default function InvestmentContextCards() {
return (
<section
aria-labelledby="investment-context-heading"
className={`${HOME_SECTION} space-y-4`}
>
<h2
id="investment-context-heading"
className={HOME_SECTION_HEADING}
>
Encontre o contexto do seu investimento
</h2>
<InvestmentContextGrid preview />
<div className="flex justify-center">
<a
href="/contextos-de-investimento"
className={PORTAL_MORE_LINK}
>
Ver mais <ArrowRight size={14} aria-hidden="true" />
</a>
</div>
</section>
);
}