diff --git a/astro.config.mjs b/astro.config.mjs index eb7665e..091aedd 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -14,8 +14,8 @@ export default defineConfig({ redirects: { '/programs': { status: 301, destination: '/services' }, '/programs/[slug]': { status: 301, destination: '/services/[slug]' }, - // Modifiche 02: "Pilates Flow" → "Profilazione"; "Rehab" esce da Servizi e passa a Training. + // Modifiche 02: "Pilates Flow" → "Profilazione". "Rehab" esce dalla griglia Servizi e + // diventa un riquadro Training, ma la pagina dettaglio resta su /services/rehab. '/services/pilates-flow': { status: 301, destination: '/services/profilazione' }, - '/services/rehab': { status: 301, destination: '/training' }, }, }); diff --git a/src/assets/img/program-holistic-class.jpg b/src/assets/img/program-holistic-class.jpg new file mode 100644 index 0000000..ebd5028 Binary files /dev/null and b/src/assets/img/program-holistic-class.jpg differ diff --git a/src/assets/img/program-reformer-class.jpg b/src/assets/img/program-reformer-class.jpg new file mode 100644 index 0000000..52aad2d Binary files /dev/null and b/src/assets/img/program-reformer-class.jpg differ diff --git a/src/assets/img/training-coaching.jpg b/src/assets/img/training-coaching.jpg new file mode 100644 index 0000000..65c54c3 Binary files /dev/null and b/src/assets/img/training-coaching.jpg differ diff --git a/src/assets/img/training-holistic-class.jpg b/src/assets/img/training-holistic-class.jpg new file mode 100644 index 0000000..ebd5028 Binary files /dev/null and b/src/assets/img/training-holistic-class.jpg differ diff --git a/src/assets/img/training-reformer-class.jpg b/src/assets/img/training-reformer-class.jpg new file mode 100644 index 0000000..52aad2d Binary files /dev/null and b/src/assets/img/training-reformer-class.jpg differ diff --git a/src/assets/img/training-rehab.jpg b/src/assets/img/training-rehab.jpg new file mode 100644 index 0000000..56e716e Binary files /dev/null and b/src/assets/img/training-rehab.jpg differ diff --git a/src/components/home/TrainingCards.astro b/src/components/home/TrainingCards.astro index f8937a1..519812b 100644 --- a/src/components/home/TrainingCards.astro +++ b/src/components/home/TrainingCards.astro @@ -14,7 +14,7 @@ const isSwapRow = (i: number) => Math.floor(i / 2) % 2 === 1; {trainings.map((tr, i) => { const img = imgOf(tr.image); const card = ( -
+
diff --git a/src/data/content-seed.ts b/src/data/content-seed.ts index e66b407..fa1b608 100644 --- a/src/data/content-seed.ts +++ b/src/data/content-seed.ts @@ -48,6 +48,8 @@ export const contentSeed: SeedEntry[] = [ T('footer.training.2.label', site.footerTraining[1].label, []), T('footer.training.3.label', site.footerTraining[2].label, []), T('footer.training.4.label', site.footerTraining[3].label, []), + T('footer.training.5.label', site.footerTraining[4].label, []), + T('footer.training.6.label', site.footerTraining[5].label, []), T('footer.services.1.label', site.footerServices[0].label, []), T('footer.services.2.label', site.footerServices[1].label, []), T('footer.services.3.label', site.footerServices[2].label, []), @@ -272,7 +274,7 @@ 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.meta.description', 'One to One, Small Group, Rehab, Holistic Class, Reformer Class e Coaching: 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.'), diff --git a/src/data/service-icons.ts b/src/data/service-icons.ts index e2a230a..024e19d 100644 --- a/src/data/service-icons.ts +++ b/src/data/service-icons.ts @@ -9,4 +9,7 @@ export const serviceIcons: Record = { // Servizi rinominati (modifiche 02): profilazione (grafico/analisi), osteopatia (mani) 'profilazione': 'M4 20V6m5 14V4m5 16v-8m5 8V9M3 20h18', 'osteopatia': 'M8 3v7a4 4 0 008 0V3M6 14c0 4 3 7 6 7s6-3 6-7', + // Riquadri Training con pagina dettaglio + 'holistic-class': 'M12 3a3 3 0 110 6 3 3 0 010-6zm0 6v7m-4 3l4-3 4 3', + 'reformer-class': 'M3 8h18M3 16h18M6 8v8m12-8v8M9 12h6', }; diff --git a/src/data/services.ts b/src/data/services.ts index d3ffd5c..6e0eba6 100644 --- a/src/data/services.ts +++ b/src/data/services.ts @@ -7,6 +7,9 @@ export interface Service { features: string[]; faq: { q: string; a: string }[]; hasPricing: boolean; + /** false = pagina dettaglio esiste ma la voce non compare nella griglia /services + * (usata come approfondimento dai riquadri Training: Rehab, Holistic, Reformer). */ + grid?: boolean; } export const services: Service[] = [ @@ -99,6 +102,52 @@ export const services: Service[] = [ ], hasPricing: false, }, + { + // Approfondimento del riquadro Training "Rehab" (fuori dalla griglia /services). + slug: "rehab", + title: "Rehab", + subtitle: "Recupero post-infortunio, patologie muscolo-scheletriche", + excerpt: "Accompagniamo il corpo nel recupero della sua funzionalità attraverso il movimento guidato: il ponte tra la fine del percorso medico-riabilitativo e il ritorno a una vita attiva piena.", + longDescription: "Il Rehab InsanityLab significa accompagnare il corpo nel recupero della sua funzionalità attraverso il movimento guidato. Non è fisioterapia in senso clinico: è il ponte tra la fine del percorso medico-riabilitativo e il ritorno a una vita attiva piena, con la stessa cura scientifica ma in un contesto di allenamento. Il servizio lavora con un ampio spettro di condizioni e ogni situazione viene valutata singolarmente con metodologie evidence based.", + features: ["Recupero post-chirurgico e post-traumatico ortopedico", "Problemi posturali e motori", "Lombalgia e dolori cronici", "Ipertensione e patologie metaboliche", "Lipedema", "Gravidanza e periodo post-parto", "Attività motoria adattata per anziani (AFA)"], + faq: [ + { q: "Chi segue il percorso Rehab?", a: "Professionisti specializzati in rieducazione funzionale ed esercizio adattato, in sinergia con medici specialisti, fisioterapisti e osteopati." }, + { q: "Serve una diagnosi medica?", a: "Se disponibile è utile portarla alla prima consulenza; il percorso si integra con le indicazioni dei sanitari." }, + { q: "Quanto dura il percorso?", a: "Dipende dalla condizione di partenza: la progressione viene definita e aggiornata durante il percorso." }, + ], + hasPricing: false, + grid: false, + }, + { + // Approfondimento del riquadro Training "Holistic Class" (ex Pilates Flow / Performance Class). + slug: "holistic-class", + title: "Holistic Class", + subtitle: "Classi fino a 8 persone con trainer certificato", + excerpt: "Mobilità articolare, respirazione, equilibrio. Da sola o integrata nei tuoi allenamenti, adatta a tutti i livelli. Sessioni da 40 minuti.", + longDescription: "La Holistic Class lavora su mobilità articolare, respirazione ed equilibrio. Puoi seguirla da sola o integrarla nei tuoi allenamenti; è adatta a tutti i livelli e ogni sessione dura 40 minuti. Comprende lavoro di Pilates Flow, Mobility e Yoga.", + features: ["Pilates Flow", "Mobility", "Yoga", "Sessioni da 40 minuti", "Adatta a tutti i livelli"], + faq: [ + { q: "A chi è adatta la Holistic Class?", a: "A chiunque voglia migliorare mobilità, respirazione ed equilibrio, a ogni livello di partenza." }, + { q: "Posso integrarla con altri allenamenti?", a: "Sì: funziona sia come percorso a sé sia come complemento al tuo programma di allenamento." }, + ], + hasPricing: false, + grid: false, + }, + { + // Approfondimento del riquadro Training "Reformer Class" (nuova). + slug: "reformer-class", + title: "Reformer Class", + subtitle: "Classi fino a 5 persone con macchinari reformer", + excerpt: "Core, postura e mobilità su macchina reformer. Lavoro a basso impatto sulle articolazioni, adatto a tutti i livelli. Lezioni da 40 minuti.", + longDescription: "La Reformer Class utilizza i macchinari reformer per il pilates in classi fino a 5 persone. Il lavoro è dedicato a core, postura e mobilità, a basso impatto sulle articolazioni e adatto a tutti i livelli. Ogni lezione dura 40 minuti.", + features: ["Macchinari reformer", "Core, postura e mobilità", "Lavoro a basso impatto sulle articolazioni", "Classi fino a 5 persone", "Lezioni da 40 minuti"], + faq: [ + { q: "Serve esperienza con il reformer?", a: "No: le progressioni sono graduali e seguite da trainer certificati, adatte anche a chi inizia." }, + { q: "Quante persone per classe?", a: "Massimo 5, per garantire attenzione e correzione costante." }, + ], + hasPricing: false, + grid: false, + }, ]; export function getService(slug: string): Service | undefined { diff --git a/src/data/site.ts b/src/data/site.ts index a961505..87cb008 100644 --- a/src/data/site.ts +++ b/src/data/site.ts @@ -19,9 +19,11 @@ export const site = { ], footerTraining: [ { label: "One to one", href: "/training#one-to-one" }, - { label: "Small groups", href: "/training#small-groups" }, - { label: "Performance class", href: "/training#performance-class" }, - { label: "Fit remote", href: "/training#fit-remote" }, + { label: "Small group", href: "/training#small-groups" }, + { label: "Rehab", href: "/training#rehab" }, + { label: "Holistic class", href: "/training#holistic-class" }, + { label: "Reformer class", href: "/training#reformer-class" }, + { label: "Coaching", href: "/training#coaching" }, ], footerServices: [ { label: "Personal Training", href: "/services/personal-training" }, diff --git a/src/data/trainings.ts b/src/data/trainings.ts index 7d9decb..d838db5 100644 --- a/src/data/trainings.ts +++ b/src/data/trainings.ts @@ -1,6 +1,8 @@ export const trainings = [ { id: "one-to-one", title: "One to One", caption: "Allenamento con un trainer dedicato", image: "training-one-to-one", description: "Allenati con un trainer dedicato che costruisce un percorso su misura per i tuoi obiettivi. Ogni sessione one to one è pensata per migliorare performance, tecnica e risultati. Supporto costante, attenzione totale e allenamenti personalizzati per dare il massimo.", cta: { label: "Contattaci", href: "/contact" } }, - { id: "small-groups", title: "Small Groups", caption: "Mini gruppi (max 3 persone) con trainer dedicato", image: "training-small-groups", description: "Allenati in mini gruppi da massimo 3 persone con un trainer dedicato. Un’esperienza small group che unisce attenzione personalizzata, motivazione e condivisione. Programmi mirati e supporto costante per raggiungere i tuoi obiettivi insieme.", cta: { label: "Contattaci", href: "/contact" } }, - { id: "performance-class", title: "Performance Class", caption: "Classi fino a 8 persone con trainer certificato", image: "training-performance-class", description: "Allenati in classi fino a 8 persone guidate da trainer certificati. Sessioni dinamiche ad alta intensità pensate per migliorare forza, resistenza e performance. Energia, motivazione e allenamenti strutturati per dare il massimo in ogni workout.", cta: { label: "Scopri", href: "/services/performance-class" } }, - { id: "fit-remote", title: "Fit Remote", caption: "Piano di allenamento su misura, ovunque ti alleni.", image: "training-fit-remote", description: "Con Fit Remote hai un piano di allenamento su misura, ovunque ti alleni. Programmi personalizzati creati sui tuoi obiettivi, da seguire in palestra, a casa o in viaggio. Supporto costante e allenamenti pensati per adattarsi al tuo stile di vita.", cta: { label: "Contattaci", href: "/contact" } }, + { id: "small-groups", title: "Small Group", caption: "Mini gruppi (max 4 persone) con trainer dedicato", image: "training-small-groups", description: "Allenati in mini gruppi da massimo 4 persone con un trainer dedicato. Un’esperienza small group che unisce attenzione personalizzata, motivazione e condivisione. Programmi mirati e supporto costante per raggiungere i tuoi obiettivi insieme.", cta: { label: "Contattaci", href: "/contact" } }, + { id: "rehab", title: "Rehab", caption: "Recupero funzionale attraverso il movimento guidato", image: "training-rehab", description: "Il Rehab InsanityLab accompagna il corpo nel recupero della sua funzionalità attraverso il movimento guidato: il ponte tra la fine del percorso medico-riabilitativo e il ritorno a una vita attiva piena, con la stessa cura scientifica ma in un contesto di allenamento.", cta: { label: "Scopri", href: "/services/rehab" } }, + { id: "holistic-class", title: "Holistic Class", caption: "Classi fino a 8 persone con trainer certificato", image: "training-holistic-class", description: "Mobilità articolare, respirazione, equilibrio. Da sola o integrata nei tuoi allenamenti, adatta a tutti i livelli. Sessioni da 40 minuti che uniscono Pilates Flow, Mobility e Yoga.", cta: { label: "Scopri", href: "/services/holistic-class" } }, + { id: "reformer-class", title: "Reformer Class", caption: "Classi fino a 5 persone con macchinari reformer", image: "training-reformer-class", description: "Core, postura e mobilità su macchina reformer. Lavoro a basso impatto sulle articolazioni, adatto a tutti i livelli. Lezioni da 40 minuti in classi fino a 5 persone.", cta: { label: "Scopri", href: "/services/reformer-class" } }, + { id: "coaching", title: "Coaching", caption: "Programma su misura e monitoraggio, anche online", image: "training-coaching", description: "Con il coaching hai un programma di allenamento su misura e un monitoraggio costante, ovunque ti alleni: in palestra, a casa o in viaggio. Il percorso sviluppa autonomia e continuità, adattandosi al tuo stile di vita (anche online, formula Fit Remote).", cta: { label: "Scopri", href: "/services/coaching" } }, ] as const; diff --git a/src/lib/db.ts b/src/lib/db.ts index 0036f1b..c36c21e 100644 --- a/src/lib/db.ts +++ b/src/lib/db.ts @@ -126,6 +126,14 @@ export function createDb(path?: string): Database.Database { ['services.meta.description', 'I servizi InsanityLab: Personal Training, Performance Class, Coaching, Pilates Flow, Rehab e Nutrizione.', 'I servizi InsanityLab: Personal Training, Performance Class, Coaching, Profilazione, Osteopatia e Nutrizione.'], + // Pagina Training: riquadri passati a One to One, Small Group, Rehab, Holistic Class, + // Reformer Class, Coaching. Label footer + meta aggiornate (righe 5-6 sono nuovi tag). + ['footer.training.2.label', 'Small groups', 'Small group'], + ['footer.training.3.label', 'Performance class', 'Rehab'], + ['footer.training.4.label', 'Fit remote', 'Holistic class'], + ['training.meta.description', + 'One to One, Small Groups, Performance Class e Fit Remote: trova il training InsanityLab più adatto a te.', + 'One to One, Small Group, Rehab, Holistic Class, Reformer Class e Coaching: trova il training InsanityLab più adatto a te.'], ]; const upd02 = db.prepare('UPDATE content_blocks SET value = ? WHERE tag = ? AND value = ?'); const upd02Tx = db.transaction(() => { for (const [tag, oldV, newV] of SERVIZI_02) upd02.run(newV, tag, oldV); }); diff --git a/src/pages/services/[slug].astro b/src/pages/services/[slug].astro index ee3b1d9..3a31714 100644 --- a/src/pages/services/[slug].astro +++ b/src/pages/services/[slug].astro @@ -13,7 +13,7 @@ export const prerender = false; const service = getService(Astro.params.slug!); if (!service) return new Response(null, { status: 404 }); const slug = service.slug; -const others = services.filter((p) => p.slug !== service.slug); +const others = services.filter((p) => p.slug !== service.slug && p.grid !== false); const images = import.meta.glob<{ default: ImageMetadata }>('../../assets/img/program-*.jpg', { eager: true }); const imgOf = (slug: string) => Object.entries(images).find(([p]) => p.includes(`program-${slug}.`))?.[1]?.default; const heroImg = imgOf(service.slug); diff --git a/src/pages/services/index.astro b/src/pages/services/index.astro index 80a4bb0..f5f9627 100644 --- a/src/pages/services/index.astro +++ b/src/pages/services/index.astro @@ -8,6 +8,7 @@ import TImg from '../../components/content/TImg.astro'; import { t } from '../../lib/content'; const images = import.meta.glob<{ default: ImageMetadata }>('../../assets/img/program-*.jpg', { eager: true }); const imgOf = (slug: string) => Object.entries(images).find(([p]) => p.includes(`program-${slug}.`))?.[1]?.default; +const gridServices = services.filter((p) => p.grid !== false); export const prerender = false; --- @@ -19,7 +20,7 @@ export const prerender = false;
- {services.map((p, i) => ( + {gridServices.map((p, i) => (
{imgOf(p.slug) && (