b913a2bf90
Refs gitea:Adriano/AI-OS#310 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
280 lines
15 KiB
Diff
280 lines
15 KiB
Diff
# Review package: f4c350a..3f01721
|
||
|
||
## Commits
|
||
3f01721 feat: tag contenuti home hero, info, feature, quote
|
||
|
||
## Files changed
|
||
src/components/home/FeatureBlocks.astro | 21 +++++++++---------
|
||
src/components/home/HeroSlider.astro | 12 +++++-----
|
||
src/components/home/InfoColumns.astro | 14 +++++++-----
|
||
src/components/home/QuoteBanner.astro | 13 +++++------
|
||
src/data/content-seed.ts | 39 +++++++++++++++++++++++++++++++++
|
||
src/pages/index.astro | 8 ++++---
|
||
6 files changed, 75 insertions(+), 32 deletions(-)
|
||
|
||
## Diff
|
||
diff --git a/src/components/home/FeatureBlocks.astro b/src/components/home/FeatureBlocks.astro
|
||
index f35f301..9a7ae01 100644
|
||
--- a/src/components/home/FeatureBlocks.astro
|
||
+++ b/src/components/home/FeatureBlocks.astro
|
||
@@ -1,33 +1,32 @@
|
||
---
|
||
-import { Image } from 'astro:assets';
|
||
import featPerformance from '../../assets/img/feature-performance.jpg';
|
||
import featBalance from '../../assets/img/feature-balance.jpg';
|
||
import featLongevity from '../../assets/img/feature-longevity.jpg';
|
||
+import T from '../content/T.astro';
|
||
+import TImg from '../content/TImg.astro';
|
||
+import { t } from '../../lib/content';
|
||
const blocks = [
|
||
- { title: 'PERFORMANCE', image: featPerformance, reverse: false,
|
||
- text: 'Allenamenti progettati su misura per adattarsi ai tuoi obiettivi e al tuo livello. Programmi mirati che sviluppano forza, resistenza e funzionalità in modo equilibrato. Un metodo efficace per migliorare le performance e ottenere risultati concreti e duraturi.' },
|
||
- { title: 'BALANCE', image: featBalance, reverse: true,
|
||
- text: 'L’equilibrio tra corpo e mente è la base di ogni performance duratura. Attraverso movimento, recupero e gestione dello stress, costruiamo stabilità e controllo. Un approccio integrato che sostiene benessere, energia e continuità nel tempo.' },
|
||
- { title: 'LONGEVITY', image: featLongevity, reverse: false,
|
||
- text: 'Benessere completo tra movimento, nutrizione e stile di vita. Un percorso personalizzato che unisce prevenzione, recupero ed equilibrio. Investi nella tua salute e qualità della vita nel tempo.' },
|
||
+ { key: 'performance', image: featPerformance, reverse: false },
|
||
+ { key: 'balance', image: featBalance, reverse: true },
|
||
+ { key: 'longevity', image: featLongevity, reverse: false },
|
||
];
|
||
---
|
||
<section class="section">
|
||
<div class="container">
|
||
{blocks.map((b) => (
|
||
<div class:list={['feat', { 'feat--reverse': b.reverse }]}>
|
||
- <Image src={b.image} alt={b.title} class="feat__img" widths={[500, 900]} sizes="(max-width: 767px) 100vw, 45vw" data-reveal={b.reverse ? 'right' : 'left'} />
|
||
+ <TImg tag={`home.feature.${b.key}.image`} src={b.image} alt={t(`home.feature.${b.key}.title`)} class="feat__img" widths={[500, 900]} sizes="(max-width: 767px) 100vw, 45vw" data-reveal={b.reverse ? 'right' : 'left'} />
|
||
<div class="feat__text" data-reveal={b.reverse ? 'left' : 'right'}>
|
||
- <h2>{b.title}</h2>
|
||
- <p>{b.text}</p>
|
||
- <a class="btn" href="/programs">Scopri</a>
|
||
+ <T tag={`home.feature.${b.key}.title`} as="h2" />
|
||
+ <T tag={`home.feature.${b.key}.body`} as="p" />
|
||
+ <a class="btn" href="/programs">{t(`home.feature.${b.key}.cta`)}</a>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</section>
|
||
|
||
<style>
|
||
.feat { display: grid; grid-template-columns: 1fr 1fr; gap: 60px; align-items: center; padding-block: 40px; }
|
||
.feat--reverse .feat__img { order: 2; }
|
||
.feat__text h2 { text-transform: uppercase; letter-spacing: .1em; }
|
||
diff --git a/src/components/home/HeroSlider.astro b/src/components/home/HeroSlider.astro
|
||
index b5239c1..7ce3273 100644
|
||
--- a/src/components/home/HeroSlider.astro
|
||
+++ b/src/components/home/HeroSlider.astro
|
||
@@ -1,26 +1,28 @@
|
||
---
|
||
-import { Image } from 'astro:assets';
|
||
import hero1 from '../../assets/img/hero-1.png';
|
||
+import T from '../content/T.astro';
|
||
+import TImg from '../content/TImg.astro';
|
||
+import { t } from '../../lib/content';
|
||
const slides = [
|
||
- { title: ['PERFORMANCE.', 'BALANCE.', 'LONGEVITY.'], image: hero1, alt: 'Atleti InsanityLab' },
|
||
+ { titleTags: ['home.hero.title-line-1', 'home.hero.title-line-2', 'home.hero.title-line-3'], image: hero1, alt: 'Atleti InsanityLab' },
|
||
];
|
||
---
|
||
<section class="hero" aria-label="presentazione">
|
||
{slides.map((s, i) => (
|
||
<div class:list={['hero__slide', { 'is-active': i === 0 }]}>
|
||
<div class="container hero__in">
|
||
<div class="hero__text">
|
||
- <h1>{s.title.map((line) => <span class="hero__line">{line}</span>)}</h1>
|
||
- <a class="btn" href="/programs">Scopri</a>
|
||
+ <h1>{s.titleTags.map((tag) => <T tag={tag} as="span" class="hero__line" />)}</h1>
|
||
+ <a class="btn" href="/programs">{t('home.hero.cta')}</a>
|
||
</div>
|
||
- <Image src={s.image} alt={s.alt} class="hero__img" widths={[600, 1000, 1400]} sizes="(max-width: 991px) 100vw, 60vw" loading="eager" />
|
||
+ <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>
|
||
))}
|
||
{slides.length > 1 && (
|
||
<>
|
||
<button class="hero__arrow hero__arrow--prev" aria-label="precedente">‹</button>
|
||
<button class="hero__arrow hero__arrow--next" aria-label="successiva">›</button>
|
||
</>
|
||
)}
|
||
</section>
|
||
diff --git a/src/components/home/InfoColumns.astro b/src/components/home/InfoColumns.astro
|
||
index 3adba4d..a91f7af 100644
|
||
--- a/src/components/home/InfoColumns.astro
|
||
+++ b/src/components/home/InfoColumns.astro
|
||
@@ -1,27 +1,29 @@
|
||
---
|
||
import { getImage } from 'astro:assets';
|
||
import infoPerformance from '../../assets/img/info-performance.jpg';
|
||
import infoBalance from '../../assets/img/info-balance.jpg';
|
||
import infoLongevity from '../../assets/img/info-longevity.jpg';
|
||
+import T from '../content/T.astro';
|
||
+import { contentImageUrl } from '../../lib/content';
|
||
// getImage garantisce l'emissione dell'asset anche quando il file è byte-identico
|
||
// ad altri import (Astro dedupa e non emette l'originale usato solo come background).
|
||
const cols = await Promise.all([
|
||
- { title: 'PERFORMANCE.', image: infoPerformance },
|
||
- { title: 'BALANCE.', image: infoBalance },
|
||
- { title: 'LONGEVITY.', image: infoLongevity },
|
||
-].map(async (c) => ({ ...c, bg: (await getImage({ src: c.image, width: 1200 })).src })));
|
||
+ { titleTag: 'home.info.col1.title', imageTag: 'home.info.col1.image', image: infoPerformance },
|
||
+ { titleTag: 'home.info.col2.title', imageTag: 'home.info.col2.image', image: infoBalance },
|
||
+ { titleTag: 'home.info.col3.title', imageTag: 'home.info.col3.image', image: infoLongevity },
|
||
+].map(async (c) => ({ ...c, bg: contentImageUrl(c.imageTag, (await getImage({ src: c.image, width: 1200 })).src) })));
|
||
---
|
||
<section class="info" aria-label="pilastri">
|
||
{cols.map((c, i) => (
|
||
- <a class="info__col" href="/programs" style={`background-image:url(${c.bg});--reveal-delay:${i * 0.15}s`} data-reveal="fade">
|
||
- <span class="info__title">{c.title}</span>
|
||
+ <a class="info__col" href="/programs" style={`background-image:url(${c.bg});--reveal-delay:${i * 0.15}s`} data-reveal="fade" data-tag={c.imageTag}>
|
||
+ <T tag={c.titleTag} as="span" class="info__title" />
|
||
</a>
|
||
))}
|
||
</section>
|
||
|
||
<style>
|
||
.info { display: grid; grid-template-columns: repeat(3, 1fr); }
|
||
/* Proporzioni Figma: colonna 413x308 su frame 1209 — l'altezza scala con la larghezza */
|
||
.info__col { position: relative; aspect-ratio: 413 / 308; min-height: 320px; background-size: cover; background-position: center; display: flex; align-items: center; justify-content: center; text-decoration: none; }
|
||
.info__col::before { content: ''; position: absolute; inset: 0; background: rgba(30,24,20,.35); transition: background .2s; }
|
||
.info__col:hover::before { background: rgba(30,24,20,.15); }
|
||
diff --git a/src/components/home/QuoteBanner.astro b/src/components/home/QuoteBanner.astro
|
||
index 8ffaeeb..26247e7 100644
|
||
--- a/src/components/home/QuoteBanner.astro
|
||
+++ b/src/components/home/QuoteBanner.astro
|
||
@@ -1,29 +1,28 @@
|
||
---
|
||
import { getImage } from 'astro:assets';
|
||
import quoteBgSrc from '../../assets/img/quote-bg.jpg';
|
||
-const quoteBg = await getImage({ src: quoteBgSrc, width: 1920 });
|
||
-const quote = 'PERFORMANCE È SPINGERE OLTRE I PROPRI LIMITI, BALANCE È SAPERLI ASCOLTARE, LONGEVITY È COSTRUIRE NEL TEMPO CIÒ CHE DAVVERO CONTA.';
|
||
-const quoteHtml = quote.replace(/(PERFORMANCE|BALANCE|LONGEVITY)/g, '<strong>$1</strong>');
|
||
+import { t, contentImageUrl } from '../../lib/content';
|
||
+const quoteBg = contentImageUrl('home.quote.image', (await getImage({ src: quoteBgSrc, width: 1920 })).src);
|
||
---
|
||
<section class="quote" data-parallax>
|
||
- <div class="quote__bg" style={`background-image:url(${quoteBg.src})`}></div>
|
||
+ <div class="quote__bg" style={`background-image:url(${quoteBg})`} data-tag="home.quote.image"></div>
|
||
<div class="quote__in">
|
||
<p class="quote__mark">“</p>
|
||
<blockquote>
|
||
<div class="quote__marquee">
|
||
<p class="quote__track">
|
||
- <span class="quote__seg" set:html={quoteHtml} />
|
||
- <span class="quote__seg" aria-hidden="true" set:html={quoteHtml} />
|
||
+ <span class="quote__seg" data-tag="home.quote.text" set:html={t('home.quote.text')} />
|
||
+ <span class="quote__seg" aria-hidden="true" data-tag="home.quote.text" set:html={t('home.quote.text')} />
|
||
</p>
|
||
</div>
|
||
- <cite>Insanitylab</cite>
|
||
+ <cite data-tag="home.quote.cite">{t('home.quote.cite')}</cite>
|
||
</blockquote>
|
||
</div>
|
||
</section>
|
||
|
||
<style>
|
||
.quote { position: relative; overflow: hidden; text-align: center; }
|
||
/* Sfondo su div dedicato, esteso oltre i bordi per il margine di corsa del parallax */
|
||
.quote__bg { position: absolute; inset: -120px 0; background-size: cover; background-position: center; transform: translateY(var(--parallax-y, 0)); will-change: transform; }
|
||
.quote__bg::after { content: ''; position: absolute; inset: 0; background: rgba(46,32,24,.82); }
|
||
.quote__in { position: relative; padding-block: 110px; }
|
||
diff --git a/src/data/content-seed.ts b/src/data/content-seed.ts
|
||
index 93deb38..dfecec8 100644
|
||
--- a/src/data/content-seed.ts
|
||
+++ b/src/data/content-seed.ts
|
||
@@ -51,14 +51,53 @@ export const contentSeed: SeedEntry[] = [
|
||
// --- Contact form ---
|
||
T('form.field.first-name', 'Nome', []),
|
||
T('form.field.last-name', 'Cognome', []),
|
||
T('form.field.phone', 'Telefono', []),
|
||
T('form.field.email', 'E-mail', []),
|
||
T('form.field.message', 'Messaggio', []),
|
||
T('form.submit', 'Invia messaggio'),
|
||
T('form.msg.success', 'Messaggio inviato, ti ricontatteremo al più presto.', []),
|
||
T('form.msg.error-generic', 'Errore di invio, riprova più tardi.', []),
|
||
T('form.msg.error-network', 'Errore di rete, riprova più tardi.', []),
|
||
+
|
||
+ // --- Home: meta, training heading ---
|
||
+ T('home.meta.title', 'Performance. Balance. Longevity.', []),
|
||
+ T('home.training.title', 'Training'),
|
||
+ T('home.training.subtitle', 'Porta i tuoi allenamenti al livello successivo: trova il percorso più adatto alle tue esigenze.'),
|
||
+
|
||
+ // --- Home: hero ---
|
||
+ T('home.hero.title-line-1', 'PERFORMANCE.'),
|
||
+ T('home.hero.title-line-2', 'BALANCE.'),
|
||
+ T('home.hero.title-line-3', 'LONGEVITY.'),
|
||
+ T('home.hero.cta', 'Scopri'),
|
||
+ I('home.hero.image'),
|
||
+
|
||
+ // --- Home: info columns ---
|
||
+ T('home.info.col1.title', 'PERFORMANCE.'),
|
||
+ T('home.info.col2.title', 'BALANCE.'),
|
||
+ T('home.info.col3.title', 'LONGEVITY.'),
|
||
+ I('home.info.col1.image'),
|
||
+ I('home.info.col2.image'),
|
||
+ I('home.info.col3.image'),
|
||
+
|
||
+ // --- Home: feature blocks ---
|
||
+ T('home.feature.performance.title', 'PERFORMANCE'),
|
||
+ T('home.feature.performance.body', 'Allenamenti progettati su misura per adattarsi ai tuoi obiettivi e al tuo livello. Programmi mirati che sviluppano forza, resistenza e funzionalità in modo equilibrato. Un metodo efficace per migliorare le performance e ottenere risultati concreti e duraturi.'),
|
||
+ T('home.feature.performance.cta', 'Scopri'),
|
||
+ T('home.feature.balance.title', 'BALANCE'),
|
||
+ T('home.feature.balance.body', 'L’equilibrio tra corpo e mente è la base di ogni performance duratura. Attraverso movimento, recupero e gestione dello stress, costruiamo stabilità e controllo. Un approccio integrato che sostiene benessere, energia e continuità nel tempo.'),
|
||
+ T('home.feature.balance.cta', 'Scopri'),
|
||
+ T('home.feature.longevity.title', 'LONGEVITY'),
|
||
+ T('home.feature.longevity.body', 'Benessere completo tra movimento, nutrizione e stile di vita. Un percorso personalizzato che unisce prevenzione, recupero ed equilibrio. Investi nella tua salute e qualità della vita nel tempo.'),
|
||
+ T('home.feature.longevity.cta', 'Scopri'),
|
||
+ I('home.feature.performance.image'),
|
||
+ I('home.feature.balance.image'),
|
||
+ I('home.feature.longevity.image'),
|
||
+
|
||
+ // --- Home: quote banner ---
|
||
+ H('home.quote.text', '<strong>PERFORMANCE</strong> È SPINGERE OLTRE I PROPRI LIMITI, <strong>BALANCE</strong> È SAPERLI ASCOLTARE, <strong>LONGEVITY</strong> È COSTRUIRE NEL TEMPO CIÒ CHE DAVVERO CONTA.'),
|
||
+ T('home.quote.cite', 'Insanitylab', []),
|
||
+ I('home.quote.image'),
|
||
// I task di estrazione aggiungono qui le entry di header/footer/pagine/data file.
|
||
];
|
||
|
||
export const seedByTag = new Map(contentSeed.map((e) => [e.tag, e]));
|
||
diff --git a/src/pages/index.astro b/src/pages/index.astro
|
||
index 665a928..a99d529 100644
|
||
--- a/src/pages/index.astro
|
||
+++ b/src/pages/index.astro
|
||
@@ -3,30 +3,32 @@ import Base from '../layouts/Base.astro';
|
||
import HeroSlider from '../components/home/HeroSlider.astro';
|
||
import InfoColumns from '../components/home/InfoColumns.astro';
|
||
import FeatureBlocks from '../components/home/FeatureBlocks.astro';
|
||
import QuoteBanner from '../components/home/QuoteBanner.astro';
|
||
import TrainingCards from '../components/home/TrainingCards.astro';
|
||
import ProgramsGrid from '../components/home/ProgramsGrid.astro';
|
||
import Agenda from '../components/Agenda.astro';
|
||
import TeamSection from '../components/home/TeamSection.astro';
|
||
import MethodSteps from '../components/home/MethodSteps.astro';
|
||
import PartnersStrip from '../components/home/PartnersStrip.astro';
|
||
+import T from '../components/content/T.astro';
|
||
+import { t } from '../lib/content';
|
||
export const prerender = true;
|
||
---
|
||
-<Base title="Performance. Balance. Longevity.">
|
||
+<Base title={t('home.meta.title')}>
|
||
<HeroSlider />
|
||
<InfoColumns />
|
||
<FeatureBlocks />
|
||
<QuoteBanner />
|
||
<section class="section" style="padding-bottom:0">
|
||
<div class="section-heading">
|
||
- <h2>Training</h2>
|
||
- <p>Porta i tuoi allenamenti al livello successivo: trova il percorso più adatto alle tue esigenze.</p>
|
||
+ <T tag="home.training.title" as="h2" />
|
||
+ <T tag="home.training.subtitle" as="p" />
|
||
</div>
|
||
</section>
|
||
<TrainingCards />
|
||
<ProgramsGrid />
|
||
<Agenda />
|
||
<TeamSection />
|
||
<MethodSteps />
|
||
<PartnersStrip />
|
||
</Base>
|