Contatti obbligatori, hero senza foto, menu Promo2 solo admin
- Contatti: nome, cognome, telefono e mail resi obbligatori (validazione client + server); il form del footer ora include cognome e telefono. - Home hero: rimossa la foto (file conservato su disco), fascia ridotta da 100vh a padding contenuto, testo allargato. - Menu: la voce "Promo 2 (test)" è visibile solo agli admin loggati. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,8 +14,8 @@ const { variant = 'full' } = Astro.props;
|
||||
data-msg-error-network={t('form.msg.error-network')}
|
||||
>
|
||||
<input class="field" name="firstName" placeholder={t('form.field.first-name')} required maxlength="100" />
|
||||
{variant === 'full' && <input class="field" name="lastName" placeholder={t('form.field.last-name')} maxlength="100" />}
|
||||
{variant === 'full' && <input class="field" name="phone" placeholder={t('form.field.phone')} maxlength="40" />}
|
||||
<input class="field" name="lastName" placeholder={t('form.field.last-name')} required maxlength="100" />
|
||||
<input class="field" type="tel" name="phone" placeholder={t('form.field.phone')} required maxlength="40" />
|
||||
<input class="field" type="email" name="email" placeholder={t('form.field.email')} required maxlength="200" />
|
||||
<textarea class="field" name="message" placeholder={t('form.field.message')} required maxlength="5000"></textarea>
|
||||
<input class="hp" type="text" name="website" tabindex="-1" autocomplete="off" />
|
||||
|
||||
@@ -16,7 +16,9 @@ const areaHref = user?.role === 'superuser' ? '/admin/content' : '/admin';
|
||||
<a href="/" class="hdr__logo"><img src={contentImageUrl('header.logo.image', '/img/logo-dark.png')} alt={t('header.logo.alt')} width="150" /></a>
|
||||
<nav class="hdr__nav" id="site-nav" aria-label="principale">
|
||||
{site.navigation.map((item, i) => (
|
||||
<a href={item.href} class:list={['hdr__link', { 'is-active': path === item.href || (item.href !== '/' && path.startsWith(item.href)) }]}>{t(`global.nav.${i + 1}.label`)}</a>
|
||||
(!('adminOnly' in item && item.adminOnly) || user?.role === 'admin') && (
|
||||
<a href={item.href} class:list={['hdr__link', { 'is-active': path === item.href || (item.href !== '/' && path.startsWith(item.href)) }]}>{t(`global.nav.${i + 1}.label`)}</a>
|
||||
)
|
||||
))}
|
||||
</nav>
|
||||
<div class="hdr__user">
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
---
|
||||
import hero1 from '../../assets/img/hero-1.png';
|
||||
// Foto hero rimossa ma conservata su disco per riuso futuro: assets/img/hero-1.png
|
||||
import T from '../content/T.astro';
|
||||
import TImg from '../content/TImg.astro';
|
||||
import { t } from '../../lib/content';
|
||||
const slides = [
|
||||
{ titleTags: ['home.hero.title-line-1', 'home.hero.title-line-2', 'home.hero.title-line-3'], image: hero1, alt: 'Atleti InsanityLab' },
|
||||
{ titleTags: ['home.hero.title-line-1', 'home.hero.title-line-2', 'home.hero.title-line-3'] },
|
||||
];
|
||||
---
|
||||
<section class="hero" aria-label="presentazione">
|
||||
@@ -15,7 +14,6 @@ const slides = [
|
||||
<h1>{s.titleTags.map((tag) => <T tag={tag} as="span" class="hero__line" />)}</h1>
|
||||
<a class="btn" href="/services">{t('home.hero.cta')}</a>
|
||||
</div>
|
||||
<TImg tag="home.hero.image" src={s.image} alt={s.alt} class="hero__img" widths={[600, 1000, 1400]} sizes="(max-width: 991px) 100vw, 60vw" loading="eager" />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
@@ -34,32 +32,28 @@ const slides = [
|
||||
.hero__slide.is-active { display: block; }
|
||||
/* Come nel Figma: figure a piena altezza ancorate in basso a destra,
|
||||
testo sovrapposto sulla sinistra. */
|
||||
.hero__in { position: relative; display: flex; align-items: center; min-height: calc(100vh - var(--header-h)); }
|
||||
.hero__in { position: relative; display: flex; align-items: center; min-height: 0; padding-block: 90px; }
|
||||
/* Lo span .hero__line è reso dal componente <T> e non riceve il data-astro-cid
|
||||
di questo componente: si ancora a .hero__text (che il cid ce l'ha) + :global. */
|
||||
.hero__text h1 :global(.hero__line) { display: block; }
|
||||
.hero__text { position: relative; z-index: 1; max-width: 46%; }
|
||||
.hero__text { position: relative; z-index: 1; max-width: 640px; }
|
||||
.hero__text h1 { font-weight: 500; }
|
||||
.hero__img { position: absolute; right: 0; bottom: 0; height: 100%; width: auto; max-width: 80%; object-fit: contain; object-position: right bottom; }
|
||||
.hero__arrow { position: absolute; top: 50%; transform: translateY(-50%); background: none; border: 0; font-size: 3rem; color: var(--c-heading); cursor: pointer; }
|
||||
.hero__arrow--prev { left: 12px; } .hero__arrow--next { right: 12px; }
|
||||
@media (max-width: 991px) {
|
||||
.hero__in { flex-direction: column; align-items: flex-start; padding-block: 40px; min-height: 0; gap: 24px; }
|
||||
.hero__text { max-width: none; }
|
||||
.hero__img { position: static; max-width: 100%; height: auto; }
|
||||
}
|
||||
|
||||
/* Ingresso al load stile Slider Revolution del template */
|
||||
@keyframes hero-up { from { opacity: 0; transform: translateY(60px); } to { opacity: 1; transform: none; } }
|
||||
@keyframes hero-side { from { opacity: 0; transform: translateX(60px); } to { opacity: 1; transform: none; } }
|
||||
:global(html.js) .hero__text h1 :global(.hero__line) { opacity: 0; animation: hero-up .8s ease forwards; }
|
||||
:global(html.js) .hero__text h1 :global(.hero__line:nth-child(1)) { animation-delay: .15s; }
|
||||
:global(html.js) .hero__text h1 :global(.hero__line:nth-child(2)) { animation-delay: .3s; }
|
||||
:global(html.js) .hero__text h1 :global(.hero__line:nth-child(3)) { animation-delay: .45s; }
|
||||
:global(html.js) .hero__text .btn { opacity: 0; animation: hero-up .8s ease .7s forwards; }
|
||||
:global(html.js) .hero__img { opacity: 0; animation: hero-side 1s ease .2s forwards; }
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
:global(html.js) .hero__text h1 :global(.hero__line), :global(html.js) .hero__text .btn, :global(html.js) .hero__img { opacity: 1; animation: none; }
|
||||
:global(html.js) .hero__text h1 :global(.hero__line), :global(html.js) .hero__text .btn { opacity: 1; animation: none; }
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
+2
-1
@@ -18,7 +18,8 @@ export const site = {
|
||||
{ label: "Blog & Edugo", href: "/blog" },
|
||||
{ label: "Promo ed eventi", href: "/promo-eventi" },
|
||||
{ label: "Contatti", href: "/contact" },
|
||||
{ label: "Promo 2 (test)", href: "/promo-eventi2" },
|
||||
// Pagina di test: visibile solo agli admin loggati, nascosta al pubblico.
|
||||
{ label: "Promo 2 (test)", href: "/promo-eventi2", adminOnly: true },
|
||||
],
|
||||
footerTraining: [
|
||||
{ label: "One to one", href: "/training#one-to-one" },
|
||||
|
||||
@@ -24,6 +24,8 @@ export function validateContact(data: unknown):
|
||||
};
|
||||
if (value.website) return { ok: false, error: 'Richiesta non valida.' };
|
||||
if (!value.firstName) return { ok: false, error: 'Il nome è obbligatorio.' };
|
||||
if (!value.lastName) return { ok: false, error: 'Il cognome è obbligatorio.' };
|
||||
if (!value.phone) return { ok: false, error: 'Il telefono è obbligatorio.' };
|
||||
if (!EMAIL_RE.test(value.email)) return { ok: false, error: 'Inserisci una e-mail valida.' };
|
||||
if (!value.message) return { ok: false, error: 'Il messaggio è obbligatorio.' };
|
||||
if (value.message.length > 5000) return { ok: false, error: 'Messaggio troppo lungo.' };
|
||||
|
||||
Reference in New Issue
Block a user