Files
InsanityLab-web/.superpowers/sdd/review-f4c350a..3f01721.diff
T
Adriano b913a2bf90 registri dei piani in git (AI-OS#309)
Refs gitea:Adriano/AI-OS#310

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-06 10:36:26 +02:00

280 lines
15 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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>