aspireves.org/src/pages/spectacles/[id].astro

186 lines
8 KiB
Text
Raw Normal View History

---
import Layout from '../../layouts/Layout.astro';
import { Icon } from 'astro-icon/components';
import { getLiveStory, storyblokEditable } from '@storyblok/astro';
import { fetchSpectacles, fetchAgenda, mapStoryToSpectacle } from '../../lib/storyblok';
// Requis pour le build statique (ignoré en SSR)
export async function getStaticPaths() {
const [spectacles, agenda] = await Promise.all([fetchSpectacles(), fetchAgenda()]);
return spectacles.map(s => ({
params: { id: s.id },
props: {
spectacle: s,
upcomingDates: agenda
.filter(event => event.spectacleId === s.id)
.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()),
},
}));
}
const { id } = Astro.params;
const liveStory = await getLiveStory(Astro);
let spectacle;
let upcomingDates;
if (liveStory) {
spectacle = mapStoryToSpectacle(liveStory);
const agenda = await fetchAgenda();
upcomingDates = agenda
.filter(event => event.spectacleId === spectacle.id)
.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
} else if (Astro.props.spectacle) {
({ spectacle, upcomingDates } = Astro.props);
} else {
const [spectacles, agenda] = await Promise.all([fetchSpectacles(), fetchAgenda()]);
spectacle = spectacles.find(s => s.id === id);
upcomingDates = agenda
.filter(event => event.spectacleId === id)
.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
}
if (!spectacle) {
return Astro.redirect('/spectacles/');
}
---
<Layout title={`${spectacle.title} — Compagnie AspiRêves`}>
<div {...storyblokEditable(spectacle._blok)} class="pt-24 md:pt-32 pb-24 min-h-screen bg-cloud overflow-hidden relative">
<!-- Background -->
<div class="absolute top-0 right-0 w-96 h-96 bg-dream-purple/20 rounded-full filter blur-[100px] -translate-y-1/2 translate-x-1/2"></div>
<div class="absolute bottom-0 left-0 w-96 h-96 bg-dream-blue/20 rounded-full filter blur-[100px] translate-y-1/2 -translate-x-1/2"></div>
<div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
<!-- Back button -->
<a
href="/spectacles/"
class="animate-entrance group flex items-center gap-3 mb-10 font-sans font-bold text-night/60 hover:text-dream-purple transition-colors"
>
<Icon name="lucide:arrow-left" size={20} class="group-hover:-translate-x-1 transition-transform" />
Tous les spectacles
</a>
<!-- Hero -->
<div class="flex flex-col md:flex-row gap-10 md:gap-16 items-center mb-16 md:mb-24">
<div class="fade-scale w-full md:w-2/5">
<div class="relative overflow-hidden rounded-2xl md:rounded-3xl shadow-2xl shadow-night/10 border-4 border-white">
<img
src={spectacle.affiche}
alt={spectacle.title}
class="w-full h-auto"
referrerpolicy="no-referrer"
/>
</div>
</div>
<div class="fade-up w-full md:w-3/5 space-y-6 text-center md:text-left" style="transition-delay: 0.2s">
{spectacle.retired && (
<div class="inline-block px-4 py-1 rounded-full bg-night/10 text-night/50 font-sans text-xs font-bold uppercase tracking-widest">
Spectacle retraité
</div>
)}
<h1 class="font-display text-4xl sm:text-6xl md:text-7xl text-night">{spectacle.title}</h1>
<div class="flex flex-wrap justify-center md:justify-start gap-3">
<div class="flex items-center gap-2 bg-dream-blue/20 px-5 py-2 rounded-2xl text-sm font-sans font-bold">
<Icon name="lucide:users" size={16} class="text-dream-blue" />
<span>{spectacle.age}</span>
</div>
{spectacle.duration && (
<div class="flex items-center gap-2 bg-dream-pink/20 px-5 py-2 rounded-2xl text-sm font-sans font-bold">
<Icon name="lucide:clock" size={16} class="text-dream-pink" />
<span>{spectacle.duration}</span>
</div>
)}
</div>
{spectacle.summary && (
<p class="font-sans text-lg md:text-xl text-night/70 leading-relaxed whitespace-pre-line">{spectacle.summary}</p>
)}
{spectacle.credits && (
<p class="font-sans text-sm text-night/50 font-bold uppercase tracking-widest">{spectacle.credits}</p>
)}
{spectacle.dossierPro && spectacle.dossierPro !== '#' && (
<a
href={spectacle.dossierPro}
target="_blank"
rel="noreferrer"
class="inline-flex items-center gap-3 bg-night text-cloud px-8 py-4 rounded-full font-sans font-bold tracking-wide hover:bg-night/90 transition-all hover:scale-105 shadow-lg shadow-night/20"
>
<Icon name="lucide:download" size={18} />
Dossier Pédagogique
</a>
)}
</div>
</div>
<!-- Gallery -->
{spectacle.gallery.length > 0 && (
<section class="fade-up mb-16 md:mb-24">
<h2 class="font-display text-3xl md:text-5xl text-night mb-8 md:mb-12 text-center">Galerie</h2>
<div class="columns-1 sm:columns-2 gap-6 md:gap-8">
{spectacle.gallery.map((img, index) => (
<div class="mb-6 md:mb-8 break-inside-avoid overflow-hidden rounded-2xl md:rounded-3xl shadow-xl shadow-night/5 border-4 border-white">
<img
src={img}
alt={`${spectacle.title} - photo ${index + 1}`}
class="w-full h-auto"
referrerpolicy="no-referrer"
/>
</div>
))}
</div>
</section>
)}
<!-- Upcoming dates -->
{upcomingDates.length > 0 && (
<section class="fade-up">
<h2 class="font-display text-3xl md:text-5xl text-night mb-8 md:mb-12 text-center">Prochaines dates</h2>
<div class="space-y-4 max-w-2xl mx-auto">
{upcomingDates.map(event => {
const dateObj = new Date(event.date);
return (
<div class="flex flex-col sm:flex-row gap-6 p-6 md:p-8 rounded-[24px] bg-white shadow-lg shadow-night/5 border border-dream-purple/10 items-center">
<div class="flex-shrink-0 flex flex-col items-center justify-center w-20 h-20 md:w-24 md:h-24 rounded-2xl bg-gradient-to-br from-dream-purple to-dream-blue text-white shadow-md">
<span class="font-sans text-[10px] md:text-xs font-bold uppercase tracking-widest opacity-80">
{dateObj.toLocaleString('fr-FR', { month: 'short' })}
</span>
<span class="font-display text-3xl md:text-4xl">
{dateObj.getDate()}
</span>
</div>
<div class="flex-grow text-center sm:text-left">
<div class="flex items-center justify-center sm:justify-start gap-2 font-sans text-sm text-night/50 mb-1">
<Icon name="lucide:calendar" size={14} />
<span>{dateObj.toLocaleString('fr-FR', { weekday: 'long', hour: '2-digit', minute: '2-digit' })}</span>
</div>
<div class="flex items-center justify-center sm:justify-start gap-2 font-sans font-bold text-night">
<Icon name="lucide:map-pin" size={14} class="text-dream-coral" />
<span>{event.location}</span>
</div>
</div>
{event.bookingLink && (
<a
href={event.bookingLink}
target="_blank"
rel="noreferrer"
class="bg-dream-coral text-white px-6 py-3 rounded-full font-sans font-bold text-sm hover:scale-105 transition-transform shadow-md"
>
Réserver
</a>
)}
</div>
);
})}
</div>
</section>
)}
</div>
</div>
</Layout>