Aggiorna la sezione Infrastruttura con carosello minicard e uniforma i loghi.

Sostituisce il vecchio slider ecosistema con un carosello automatico di badge+slogan e allinea il logo AWS alla palette monocromatica del sito.

Made-with: Cursor
This commit is contained in:
Javaxman
2026-04-23 12:20:33 +02:00
parent a81ed6f76b
commit 857b965cd4
4 changed files with 189 additions and 94 deletions

5
public/logos/aws.svg Normal file
View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 96 32" aria-hidden="true">
<text x="2" y="18" font-size="18" font-weight="700" fill="#94a3b8" font-family="Inter, Arial, sans-serif">aws</text>
<path d="M4 24c12 7 38 8 56 1" fill="none" stroke="#94a3b8" stroke-width="3.2" stroke-linecap="round" />
<path d="M58 23l6 1-4 5" fill="#94a3b8" />
</svg>

After

Width:  |  Height:  |  Size: 358 B

View File

@ -97,10 +97,51 @@ export const stackSection = {
],
},
cloudflareBadge: {
label: 'Cloudflare',
label: 'Ecosistema Cloudflare',
slogan: '«Aiutiamo a costruire un Internet migliore.»',
href: 'https://www.cloudflare.com/',
/** Simple Icons, in `public/logos/cloudflare.svg` */
iconSrc: '/logos/cloudflare.svg',
iconAlt: 'Logo Cloudflare',
},
awsBadge: {
label: 'Ecosistema AWS',
slogan: '«La piattaforma cloud più completa e ampiamente adottata al mondo.»',
href: 'https://aws.amazon.com/',
iconSrc: '/logos/aws.svg',
iconAlt: 'Logo AWS',
},
infrastructureCarousel: {
ariaLabel: 'Partner infrastrutturali e tecnologici di NexStudio',
items: [
{
label: 'Ecosistema Cloudflare',
slogan: '«Aiutiamo a costruire un Internet migliore.»',
href: 'https://www.cloudflare.com/',
iconSrc: '/logos/cloudflare.svg',
iconAlt: 'Logo Cloudflare',
},
{
label: 'Ecosistema AWS',
slogan: '«La piattaforma cloud più completa e ampiamente adottata al mondo.»',
href: 'https://aws.amazon.com/',
iconSrc: '/logos/aws.svg',
iconAlt: 'Logo AWS',
},
{
label: 'Ecosistema GitHub',
slogan: '«Build and ship software on a single, collaborative platform.»',
href: 'https://github.com/',
iconSrc: '/logos/github.svg',
iconAlt: 'Logo GitHub',
},
{
label: 'Ecosistema OpenAI',
slogan: '«Build with AI that advances your mission.»',
href: 'https://openai.com/',
iconSrc: '/logos/openai.svg',
iconAlt: 'Logo OpenAI',
},
] as const,
},
} as const;

View File

@ -17,7 +17,7 @@ import {
cta,
} from '../data/home';
const techSliderItems = stackSection.techSlider.items;
const infrastructureCarouselItems = stackSection.infrastructureCarousel.items;
const path = Astro.url.pathname;
const localeMatch = path.match(/^\/(en|th)(\/|$)/);
const currentLocale = localeMatch?.[1] ?? 'it';
@ -494,46 +494,88 @@ const langMeta = {
</p>
<div
class="relative z-[1] mt-12 flex flex-col gap-8 rounded-2xl border border-orange-500/20 bg-gradient-to-br from-orange-950/20 to-nx-elevated/40 p-6 sm:flex-row sm:items-center sm:gap-10 sm:p-8"
class="relative z-[1] mt-12 rounded-2xl border border-orange-500/20 bg-gradient-to-br from-orange-950/20 to-nx-elevated/40 p-6 sm:p-8"
>
<a
href={stackSection.cloudflareBadge.href}
target="_blank"
rel="noopener noreferrer"
class="group flex shrink-0 items-center gap-4 rounded-xl border border-white/10 bg-nx-bg/60 px-5 py-4 transition hover:border-orange-400/35"
>
<img
src={stackSection.cloudflareBadge.iconSrc}
alt={stackSection.cloudflareBadge.iconAlt}
width="48"
height="48"
class="h-12 w-12 shrink-0 brightness-0 invert"
loading="lazy"
decoding="async"
/>
<div>
<p class="text-xs font-medium uppercase tracking-wider text-orange-200/90">
Infrastruttura
</p>
<p class="text-lg font-semibold text-nx-fg group-hover:text-orange-100">
{stackSection.cloudflareBadge.label}
</p>
<p class="mt-0.5 text-xs text-nx-muted">
Rete globale, sicurezza e edge
<div
class="nx-infra-carousel mt-5"
role="region"
aria-label={stackSection.infrastructureCarousel.ariaLabel}
>
<div class="nx-infra-carousel__viewport">
<div class="nx-infra-carousel__track">
{infrastructureCarouselItems.map((item) => (
<article class="nx-infra-carousel__item">
<a
href={item.href}
target="_blank"
rel="noopener noreferrer"
class="group inline-flex h-16 w-[16rem] items-center gap-3 rounded-xl border border-white/10 bg-nx-bg/60 px-4 transition hover:border-orange-400/35"
>
<img
src={item.iconSrc}
alt={item.iconAlt}
width={item.label === 'Ecosistema AWS' ? 84 : 40}
height={item.label === 'Ecosistema AWS' ? 28 : 40}
class:list={[
'shrink-0 object-contain',
item.label === 'Ecosistema AWS' ? 'h-7 w-20' : 'h-9 w-9',
]}
loading="lazy"
decoding="async"
/>
<div class="min-w-0">
<p class="text-sm font-semibold text-nx-fg group-hover:text-orange-100">
{item.label}
</p>
</div>
</a>
<div class="min-w-0 flex-1">
<h3 class="text-lg font-semibold text-nx-fg">
{stackSection.cloudflare.title}
</h3>
<p class="mt-2 text-sm leading-relaxed text-nx-muted sm:text-base">
{stackSection.cloudflare.intro}
<p class="mt-2 text-sm leading-relaxed text-nx-muted">
{item.slogan}
</p>
</article>
))}
{infrastructureCarouselItems.map((item) => (
<article class:list={['nx-infra-carousel__item', 'nx-infra-carousel__item--dup']}>
<a
href={item.href}
tabindex="-1"
target="_blank"
rel="noopener noreferrer"
aria-hidden="true"
class="group inline-flex h-16 w-[16rem] items-center gap-3 rounded-xl border border-white/10 bg-nx-bg/60 px-4"
>
<img
src={item.iconSrc}
alt=""
width={item.label === 'Ecosistema AWS' ? 84 : 40}
height={item.label === 'Ecosistema AWS' ? 28 : 40}
class:list={[
'shrink-0 object-contain',
item.label === 'Ecosistema AWS' ? 'h-7 w-20' : 'h-9 w-9',
]}
loading="lazy"
decoding="async"
/>
<div class="min-w-0">
<p class="text-sm font-semibold text-nx-fg">
{item.label}
</p>
</div>
</a>
<p class="mt-2 text-sm leading-relaxed text-nx-muted">
{item.slogan}
</p>
</article>
))}
</div>
</div>
</div>
</div>
<ul class="relative z-[1] mt-6 space-y-6">
<ul class="relative z-[1] mt-16 space-y-6 sm:mt-20">
{stackSection.cloudflare.points.map((item) => (
<li class="border-l-2 border-orange-400/40 pl-5">
<p class="font-semibold text-orange-100/95">{item.title}</p>
@ -545,7 +587,7 @@ const langMeta = {
</ul>
<div
class="mt-10 rounded-2xl border border-nx-border bg-nx-elevated/50 p-6 sm:p-8"
class="mt-14 rounded-2xl border border-nx-border bg-nx-elevated/50 p-6 sm:p-8 sm:mt-16"
>
<h3 class="text-lg font-semibold text-nx-fg">
{stackSection.continuity.title}
@ -555,63 +597,7 @@ const langMeta = {
</p>
</div>
<div
class="nx-tech-slider mt-6 sm:mt-7"
role="region"
aria-label={stackSection.techSlider.ariaLabel}
>
<div class="nx-tech-slider__viewport">
<div class="nx-tech-slider__track">
{techSliderItems.map((item) => (
<a
class="nx-tech-slider__link"
href={item.href}
target="_blank"
rel="noopener noreferrer"
aria-label={item.name}
>
<img
class:list={[
'nx-tech-slider__logo',
item.name === 'HL7 FHIR' && 'nx-tech-slider__logo--fhir',
]}
src={item.iconSrc}
alt=""
width="168"
height="48"
loading="lazy"
decoding="async"
/>
</a>
))}
{techSliderItems.map((item) => (
<a
class:list={['nx-tech-slider__link', 'nx-tech-slider__link--dup']}
href={item.href}
tabindex="-1"
target="_blank"
rel="noopener noreferrer"
aria-hidden="true"
>
<img
class:list={[
'nx-tech-slider__logo',
item.name === 'HL7 FHIR' && 'nx-tech-slider__logo--fhir',
]}
src={item.iconSrc}
alt=""
width="168"
height="48"
loading="lazy"
decoding="async"
/>
</a>
))}
</div>
</div>
</div>
<div class="mt-10">
<div class="mt-14 sm:mt-16">
<h3 class="text-lg font-semibold text-nx-fg">
{stackSection.whyThisChoice.title}
</h3>

View File

@ -204,6 +204,52 @@
0 0 96px -24px rgba(167, 139, 250, 0.14);
}
/* Stack: carosello minicard infrastruttura (logo + label + slogan) */
.nx-infra-carousel__viewport {
overflow: hidden;
mask-image: linear-gradient(
90deg,
transparent 0%,
#000 5%,
#000 95%,
transparent 100%
);
-webkit-mask-image: linear-gradient(
90deg,
transparent 0%,
#000 5%,
#000 95%,
transparent 100%
);
}
.nx-infra-carousel__track {
display: flex;
flex-wrap: nowrap;
align-items: flex-start;
width: max-content;
gap: 2.6rem;
animation: nx-infra-marquee 44s linear infinite;
will-change: transform;
}
.nx-infra-carousel__item {
display: flex;
flex: none;
width: 16rem;
flex-direction: column;
}
@keyframes nx-infra-marquee {
from {
transform: translate3d(0, 0, 0);
}
to {
transform: translate3d(-50%, 0, 0);
}
}
/* Stack: carosello loghi (marquee), fade ai bordi */
.nx-tech-slider__viewport {
overflow: hidden;
@ -292,6 +338,23 @@
}
@media (prefers-reduced-motion: reduce) {
.nx-infra-carousel__item--dup {
display: none;
}
.nx-infra-carousel__viewport {
overflow: visible;
mask-image: none;
-webkit-mask-image: none;
}
.nx-infra-carousel__track {
animation: none;
flex-wrap: wrap;
justify-content: center;
width: 100%;
}
.nx-tech-slider__link--dup {
display: none;
}