feat: tag contenuti training, contact e 404

This commit is contained in:
2026-07-05 17:04:17 +02:00
parent 31354c4457
commit bf38fc865c
5 changed files with 62 additions and 27 deletions
+3 -3
View File
@@ -2,11 +2,11 @@
import type { ImageMetadata } from 'astro';
import { getImage } from 'astro:assets';
interface Props { title: string; eyebrow?: string; bgImage?: ImageMetadata }
interface Props { title: string; eyebrow?: string; bgImage?: ImageMetadata | string }
const { title, eyebrow, bgImage } = Astro.props;
const bg = bgImage ? await getImage({ src: bgImage, width: 1920 }) : null;
const bgUrl = typeof bgImage === 'string' ? bgImage : bgImage ? (await getImage({ src: bgImage, width: 1920 })).src : null;
---
<section class:list={['phero', { 'phero--photo': bg }]} style={bg ? `background-image:url(${bg.src})` : undefined}>
<section class:list={['phero', { 'phero--photo': bgUrl }]} style={bgUrl ? `background-image:url(${bgUrl})` : undefined}>
<div class="container" data-reveal>
{eyebrow && <p class="eyebrow">{eyebrow}</p>}
<h1>{title}</h1>
+30
View File
@@ -270,6 +270,36 @@ export const contentSeed: SeedEntry[] = [
]),
]),
// --- Training: meta, hero, intro, trial ---
T('training.meta.title', 'Training', []),
T('training.meta.description', 'One to One, Small Groups, Performance Class e Fit Remote: trova il training InsanityLab più adatto a te.', []),
T('training.hero.title', 'training', []),
T('training.intro.title', 'Training'),
T('training.intro.subtitle', 'Porta i tuoi allenamenti al livello successivo: programmi completi e percorsi su misura. Trova il training più adatto alle tue esigenze.'),
T('training.trial.title', 'Prenota la lezione di prova'),
T('training.trial.body', "La lezione di prova è l'occasione perfetta per conoscere il metodo, vivere l'esperienza in prima persona e capire il percorso più adatto a te. Inizia oggi il tuo percorso: prenota la tua lezione di prova."),
T('training.trial.cta', 'Prenota', []),
I('training.trial.image'),
// --- Contact ---
T('contact.meta.title', 'Contatti', []),
T('contact.meta.description', 'Contatta InsanityLab: Via Leandro Alberti 76, Bologna. Compila il form o chiamaci per una consulenza iniziale.', []),
T('contact.hero.title', 'Contattaci', []),
I('contact.hero.image'),
T('contact.map.button', 'Carica la mappa (Google Maps)', []),
T('contact.map.note', 'La mappa viene caricata da Google solo dopo il tuo consenso.', []),
T('contact.info.address-label', 'Indirizzo'),
T('contact.info.phone-label', 'Telefono'),
T('contact.info.email-label', 'E-mail'),
T('contact.invite', 'Per informazioni o per richiedere una consulenza iniziale, compila il form. Un team specializzato ti accoglierà e ti ricontatterà al più presto, oppure lasciaci il tuo contatto.'),
// --- 404 ---
T('notfound.meta.title', 'Pagina non trovata', []),
T('notfound.eyebrow', 'Errore 404', []),
T('notfound.title', 'Pagina non trovata'),
T('notfound.body', 'La pagina che cerchi non esiste o è stata spostata.'),
T('notfound.cta', 'Torna alla home', []),
// I task di estrazione aggiungono qui le entry di header/footer/pagine/data file.
];
+7 -5
View File
@@ -1,14 +1,16 @@
---
import Base from '../layouts/Base.astro';
import T from '../components/content/T.astro';
import { t } from '../lib/content';
export const prerender = true;
---
<Base title="Pagina non trovata">
<Base title={t('notfound.meta.title')}>
<section class="section" style="text-align:center; padding-block:140px;">
<div class="container">
<p class="eyebrow">Errore 404</p>
<h1>Pagina non trovata</h1>
<p>La pagina che cerchi non esiste o è stata spostata.</p>
<a class="btn" href="/">Torna alla home</a>
<T tag="notfound.eyebrow" as="p" class="eyebrow" />
<T tag="notfound.title" as="h1" />
<T tag="notfound.body" as="p" />
<a class="btn" href="/">{t('notfound.cta')}</a>
</div>
</section>
</Base>
+13 -11
View File
@@ -4,35 +4,37 @@ import PageHero from '../components/PageHero.astro';
import ContactForm from '../components/ContactForm.astro';
import { site } from '../data/site';
import contactHero from '../assets/img/contact-hero.jpg';
import T from '../components/content/T.astro';
import { t, contentImageUrl } from '../lib/content';
export const prerender = true;
const mapsQuery = encodeURIComponent(`${site.address}, ${site.cityLine}`);
---
<Base title="Contatti" description="Contatta InsanityLab: Via Leandro Alberti 76, Bologna. Compila il form o chiamaci per una consulenza iniziale.">
<PageHero title="Contattaci" bgImage={contactHero} />
<Base title={t('contact.meta.title')} description={t('contact.meta.description')}>
<PageHero title={t('contact.hero.title')} bgImage={contentImageUrl('contact.hero.image', contactHero.src)} />
<section class="section">
<div class="container cgrid">
<div class="cmap" id="map-box">
<button class="btn btn--dark" id="map-load">Carica la mappa (Google Maps)</button>
<p class="cmap__note">La mappa viene caricata da Google solo dopo il tuo consenso.</p>
<button class="btn btn--dark" id="map-load">{t('contact.map.button')}</button>
<p class="cmap__note">{t('contact.map.note')}</p>
</div>
<ContactForm variant="full" />
</div>
<div class="container cinfo">
<div>
<h3>Indirizzo</h3>
<p>{site.address} {site.cityLine}</p>
<T tag="contact.info.address-label" as="h3" />
<p>{t('global.contact.address')} {t('global.contact.city-line')}</p>
</div>
<div>
<h3>Telefono</h3>
<p>{site.phone}</p>
<T tag="contact.info.phone-label" as="h3" />
<p>{t('global.contact.phone')}</p>
</div>
<div>
<h3>E-mail</h3>
<p><a href={`mailto:${site.email}`}>{site.email}</a></p>
<T tag="contact.info.email-label" as="h3" />
<p><a href={`mailto:${t('global.contact.email')}`}>{t('global.contact.email')}</a></p>
</div>
</div>
<div class="container">
<p class="cinvite">Per informazioni o per richiedere una consulenza iniziale, compila il form. Un team specializzato ti accoglierà e ti ricontatterà al più presto, oppure lasciaci il tuo contatto.</p>
<T tag="contact.invite" as="p" class="cinvite" />
</div>
</section>
</Base>
+9 -8
View File
@@ -7,18 +7,19 @@ import { Image } from 'astro:assets';
import { trainings } from '../data/trainings';
import trialImg from '../assets/img/trial-class.jpg';
import T from '../components/content/T.astro';
import TImg from '../components/content/TImg.astro';
import { t } from '../lib/content';
const images = import.meta.glob<{ default: ImageMetadata }>('../assets/img/training-*.{jpg,png}', { eager: true });
const imgOf = (name: string) => Object.entries(images).find(([p]) => p.includes(name))?.[1]?.default;
export const prerender = true;
---
<Base title="Training" description="One to One, Small Groups, Performance Class e Fit Remote: trova il training InsanityLab più adatto a te.">
<PageHero title="training" />
<Base title={t('training.meta.title')} description={t('training.meta.description')}>
<PageHero title={t('training.hero.title')} />
<section class="section" style="padding-bottom:0">
<div class="section-heading">
<h2>Training</h2>
<p>Porta i tuoi allenamenti al livello successivo: programmi completi e percorsi su misura. Trova il training più adatto alle tue esigenze.</p>
<T tag="training.intro.title" as="h2" />
<T tag="training.intro.subtitle" as="p" />
</div>
</section>
<TrainingCards />
@@ -42,11 +43,11 @@ export const prerender = true;
<section class="section section--alt">
<div class="container trial">
<Image src={trialImg} alt="Lezione di prova InsanityLab" widths={[500, 900]} sizes="(max-width:767px) 100vw, 45vw" data-reveal="left" />
<TImg tag="training.trial.image" src={trialImg} alt="Lezione di prova InsanityLab" widths={[500, 900]} sizes="(max-width:767px) 100vw, 45vw" data-reveal="left" />
<div data-reveal="right">
<h2>Prenota la lezione di prova</h2>
<p>La lezione di prova è l'occasione perfetta per conoscere il metodo, vivere l'esperienza in prima persona e capire il percorso più adatto a te. Inizia oggi il tuo percorso: prenota la tua lezione di prova.</p>
<a class="btn btn--dark" href="/contact">Prenota</a>
<T tag="training.trial.title" as="h2" />
<T tag="training.trial.body" as="p" />
<a class="btn btn--dark" href="/contact">{t('training.trial.cta')}</a>
</div>
</div>
</section>