feat: ajoute une page pour afficher les spectacles passés et intègre leur grille sur la page d'accueil
This commit is contained in:
parent
140666183d
commit
74cfe041ae
5 changed files with 343 additions and 39 deletions
147
src/components/GrilleSpectaclesPassés.astro
Normal file
147
src/components/GrilleSpectaclesPassés.astro
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
---
|
||||||
|
const { evenements, limite = 6, afficherLienVoirTout = true } = Astro.props;
|
||||||
|
const evenementsAffiches = evenements.slice(0, limite);
|
||||||
|
---
|
||||||
|
|
||||||
|
{evenementsAffiches.length > 0 && (
|
||||||
|
<div class="spectacles-passes">
|
||||||
|
<div class="grille-affiches">
|
||||||
|
{evenementsAffiches.map(evenement => (
|
||||||
|
evenement.affiche && (
|
||||||
|
<a href={`/evenements/${evenement.slug}`} class="affiche-link">
|
||||||
|
<img
|
||||||
|
src={evenement.affiche.fields.file.url}
|
||||||
|
alt={`Affiche de ${evenement.nom}`}
|
||||||
|
class="affiche-thumb"
|
||||||
|
/>
|
||||||
|
<div class="affiche-overlay">
|
||||||
|
<span class="affiche-nom">{evenement.nom}</span>
|
||||||
|
<span class="affiche-date">{new Date(evenement.date).toLocaleDateString("fr-FR")}</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
{afficherLienVoirTout && evenements.length > limite && (
|
||||||
|
<a href="/evenements" class="voir-tout">Voir tous nos spectacles passés →</a>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.spectacles-passes {
|
||||||
|
margin: 2rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grille-affiches {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||||
|
gap: 1.5rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.affiche-link {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||||
|
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.affiche-link:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
box-shadow: 0 8px 12px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.affiche-thumb {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
display: block;
|
||||||
|
aspect-ratio: 3/4;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.affiche-overlay {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background: linear-gradient(to top, rgba(0,0,0,0.8), transparent);
|
||||||
|
color: white;
|
||||||
|
padding: 1rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.affiche-nom {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.affiche-date {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.voir-tout {
|
||||||
|
display: inline-block;
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding: 0.75rem 1.5rem;
|
||||||
|
background-color: orange;
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
border: black solid 2px;
|
||||||
|
border-radius: 0.4rem;
|
||||||
|
font-weight: bold;
|
||||||
|
box-shadow: 0.2em 0.2em 0.5em rgba(0,0,0,0.3);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.voir-tout:hover {
|
||||||
|
background-color: darkorange;
|
||||||
|
transform: translateX(5px);
|
||||||
|
box-shadow: 0.3em 0.3em 0.7em rgba(0,0,0,0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.grille-affiches {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.affiche-overlay {
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.affiche-nom {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.affiche-date {
|
||||||
|
font-size: 0.7rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.grille-affiches {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.affiche-overlay {
|
||||||
|
padding: 0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.affiche-nom {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.affiche-date {
|
||||||
|
font-size: 0.65rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -18,6 +18,7 @@ export interface ContentFulEvenement {
|
||||||
lieuUrl: EntryFieldTypes.Text,
|
lieuUrl: EntryFieldTypes.Text,
|
||||||
position: EntryFieldTypes.Location,
|
position: EntryFieldTypes.Location,
|
||||||
affiche: EntryFieldTypes.AssetLink,
|
affiche: EntryFieldTypes.AssetLink,
|
||||||
|
album?: EntryFieldTypes.Text,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -31,7 +32,8 @@ export const evenementFromContentfull = ({
|
||||||
affiche,
|
affiche,
|
||||||
lieu,
|
lieu,
|
||||||
lieuUrl,
|
lieuUrl,
|
||||||
position
|
position,
|
||||||
|
album
|
||||||
}
|
}
|
||||||
}: Entry<ContentFulEvenement>): Évènement => ({
|
}: Entry<ContentFulEvenement>): Évènement => ({
|
||||||
nom: nom as string,
|
nom: nom as string,
|
||||||
|
|
@ -41,7 +43,8 @@ export const evenementFromContentfull = ({
|
||||||
affiche,
|
affiche,
|
||||||
lieu: lieu as string | undefined,
|
lieu: lieu as string | undefined,
|
||||||
lieuUrl: lieuUrl as string | undefined,
|
lieuUrl: lieuUrl as string | undefined,
|
||||||
position
|
position,
|
||||||
|
album: album as string | undefined
|
||||||
})
|
})
|
||||||
|
|
||||||
export const sortByDate = (evenements: Entry<ContentFulEvenement>[]): Entry<ContentFulEvenement>[] => {
|
export const sortByDate = (evenements: Entry<ContentFulEvenement>[]): Entry<ContentFulEvenement>[] => {
|
||||||
|
|
@ -55,7 +58,7 @@ export const sortByDate = (evenements: Entry<ContentFulEvenement>[]): Entry<Cont
|
||||||
type ContentfulDate = `${number}-${number}-${number}T${number}:${number}:${number}Z`
|
type ContentfulDate = `${number}-${number}-${number}T${number}:${number}:${number}Z`
|
||||||
|
|
||||||
interface Évènement {
|
interface Évènement {
|
||||||
nom: string, slug: string, description: Document, date: ContentfulDate, affiche: unknown, lieu?: string | undefined, lieuUrl?: string | undefined, position: unknown
|
nom: string, slug: string, description: Document, date: ContentfulDate, affiche: unknown, lieu?: string | undefined, lieuUrl?: string | undefined, position: unknown, album?: string | undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
function estÀVenir(évènement: Évènement): boolean {
|
function estÀVenir(évènement: Évènement): boolean {
|
||||||
|
|
@ -68,6 +71,10 @@ function estÀVenir(évènement: Évènement): boolean {
|
||||||
return (dateEvenement.getTime() - aujourdhui.getTime() >= 0);
|
return (dateEvenement.getTime() - aujourdhui.getTime() >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function estPassé(évènement: Évènement): boolean {
|
||||||
|
return !estÀVenir(évènement);
|
||||||
|
}
|
||||||
|
|
||||||
export const fetchEvenements = async () => {
|
export const fetchEvenements = async () => {
|
||||||
const entries = await contentfulClient.getEntries<ContentFulEvenement>({
|
const entries = await contentfulClient.getEntries<ContentFulEvenement>({
|
||||||
content_type: "evenement",
|
content_type: "evenement",
|
||||||
|
|
@ -78,6 +85,17 @@ export const fetchEvenements = async () => {
|
||||||
.filter(estÀVenir)
|
.filter(estÀVenir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const fetchEvenementsPassés = async () => {
|
||||||
|
const entries = await contentfulClient.getEntries<ContentFulEvenement>({
|
||||||
|
content_type: "evenement",
|
||||||
|
});
|
||||||
|
|
||||||
|
return sortByDate(entries.items)
|
||||||
|
.map(evenementFromContentfull)
|
||||||
|
.filter(estPassé)
|
||||||
|
.reverse() // Afficher les plus récents en premier
|
||||||
|
}
|
||||||
|
|
||||||
export const fetchEvenement = async (slug: string) => {
|
export const fetchEvenement = async (slug: string) => {
|
||||||
const entries = await contentfulClient.getEntries<ContentFulEvenement>({
|
const entries = await contentfulClient.getEntries<ContentFulEvenement>({
|
||||||
content_type: "evenement",
|
content_type: "evenement",
|
||||||
|
|
|
||||||
67
src/pages/evenements.astro
Normal file
67
src/pages/evenements.astro
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
---
|
||||||
|
import Layout from '../layouts/Layout.astro';
|
||||||
|
import { fetchEvenementsPassés } from "../lib/contentful";
|
||||||
|
import GrilleSpectaclesPassés from "../components/GrilleSpectaclesPassés.astro";
|
||||||
|
|
||||||
|
export const prerender = false
|
||||||
|
|
||||||
|
const evenementsPassés = await fetchEvenementsPassés()
|
||||||
|
---
|
||||||
|
|
||||||
|
<Layout title="Nos spectacles passés - Les Particules">
|
||||||
|
<main>
|
||||||
|
<a href="../" style="text-decoration: none; color: black; display: inline">
|
||||||
|
<img alt="Logo" src="/les-particules-bleu-sur-noir-pastille.svg" style="width:80px; vertical-align: middle; display: inline" />
|
||||||
|
</a>
|
||||||
|
<h1 style="display: inline; margin-left: 0.2em">
|
||||||
|
Nos spectacles passés
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
{evenementsPassés.length > 0 ? (
|
||||||
|
<div class="dates">
|
||||||
|
<p class="intro">
|
||||||
|
Découvrez les spectacles que nous avons eu le plaisir de jouer !
|
||||||
|
</p>
|
||||||
|
<GrilleSpectaclesPassés evenements={evenementsPassés} afficherLienVoirTout={false} limite={999} />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div class="dates">
|
||||||
|
<p class="intro">
|
||||||
|
Aucun spectacle passé pour le moment. Revenez bientôt !
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</main>
|
||||||
|
</Layout>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
main {
|
||||||
|
margin: auto;
|
||||||
|
padding: 1.5rem;
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 700;
|
||||||
|
margin: 0.5em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dates {
|
||||||
|
line-height: 1.6;
|
||||||
|
margin: 1rem 0;
|
||||||
|
border: 1px solid rgba(var(--accent), 25%);
|
||||||
|
background-color: white;
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 0.4rem;
|
||||||
|
box-shadow: 0.2em 0.2em 1em black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro {
|
||||||
|
font-size: 1.1em;
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
color: rgb(68,68,68);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
@ -9,22 +9,39 @@ export const prerender = false
|
||||||
|
|
||||||
const {slug} = Astro.params
|
const {slug} = Astro.params
|
||||||
|
|
||||||
const { nom, description, date, lieu, lieuUrl, affiche } = await fetchEvenement(slug)
|
const { nom, description, date, lieu, lieuUrl, affiche, album } = await fetchEvenement(slug)
|
||||||
|
|
||||||
const Wrapper = lieuUrl ? 'a' : 'div'
|
const Wrapper = lieuUrl ? 'a' : 'div'
|
||||||
|
|
||||||
---
|
---
|
||||||
<Layout>
|
<Layout>
|
||||||
<h1>{nom}</h1>
|
<h1>{nom}</h1>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
{affiche && <img alt=`Affiche de ${nom}` src={affiche?.fields.file.url} />}
|
{affiche && <img alt=`Affiche de ${nom}` src={affiche?.fields.file.url} />}
|
||||||
<Card title={date ? new Date(date as string).toLocaleDateString("fr-FR") : ""}>
|
<div class="infos">
|
||||||
<div>
|
<Card title={date ? new Date(date as string).toLocaleDateString("fr-FR") : ""}>
|
||||||
à <Wrapper target="_blank" href={lieuUrl}>{lieu}</Wrapper>
|
<div>
|
||||||
</div>
|
à <Wrapper target="_blank" href={lieuUrl}>{lieu}</Wrapper>
|
||||||
{
|
</div>
|
||||||
description && <article set:html={documentToHtmlString(description)} />
|
{
|
||||||
}
|
description && <article set:html={documentToHtmlString(description)} />
|
||||||
</Card>
|
}
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{album && (
|
||||||
|
<div class="album">
|
||||||
|
<div class="flickr-embed">
|
||||||
|
<iframe
|
||||||
|
src={`${album}/player/`}
|
||||||
|
width="100%"
|
||||||
|
height="500"
|
||||||
|
frameborder="0"
|
||||||
|
allowfullscreen
|
||||||
|
></iframe>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
|
|
@ -42,29 +59,75 @@ const Wrapper = lieuUrl ? 'a' : 'div'
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
img {
|
.content {
|
||||||
float:left;
|
display: flex;
|
||||||
width: 30%;
|
gap: 2rem;
|
||||||
margin: 1em;
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content > img {
|
||||||
|
flex: 0 0 30%;
|
||||||
|
max-width: 30%;
|
||||||
|
height: auto;
|
||||||
|
margin: 0;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.infos {
|
||||||
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
article {
|
article {
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.album {
|
||||||
|
margin: 2rem 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 80ch; /* Même largeur max que la Card */
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.album h2 {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
color: rgb(68,68,68);
|
||||||
|
}
|
||||||
|
|
||||||
|
.flickr-embed {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Styles pour rendre l'embed Flickr responsive */
|
||||||
|
.flickr-embed {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Force l'iframe Flickr à être responsive */
|
||||||
|
.flickr-embed iframe {
|
||||||
|
max-width: 100% !important;
|
||||||
|
width: 100% !important;
|
||||||
|
min-height: 400px;
|
||||||
|
height: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flickr-embed img {
|
||||||
|
max-width: 100% !important;
|
||||||
|
height: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 48em) {
|
@media (max-width: 48em) {
|
||||||
.content {
|
.content {
|
||||||
display: flex;
|
flex-direction: column;
|
||||||
flex-direction: column-reverse;
|
}
|
||||||
|
|
||||||
img {
|
.content > img {
|
||||||
float:none;
|
width: 100%;
|
||||||
width: 100%;
|
border: black solid 0.1em;
|
||||||
border: black solid 0.1em;
|
border-radius: 1em;
|
||||||
border-radius: 1em;
|
margin: 0 auto 1em;
|
||||||
margin: 1em auto;
|
box-shadow: 0.2em 0.2em 1em black;
|
||||||
box-shadow: 0.2em 0.2em 1em black;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
---
|
---
|
||||||
import Layout from '../layouts/Layout.astro';
|
import Layout from '../layouts/Layout.astro';
|
||||||
import Card from '../components/Card.astro';
|
import Card from '../components/Card.astro';
|
||||||
import { fetchEvenements } from "../lib/contentful";
|
import { fetchEvenements, fetchEvenementsPassés } from "../lib/contentful";
|
||||||
import Evenement from "../components/Evenement.astro";
|
import Evenement from "../components/Evenement.astro";
|
||||||
import FlickrGallery from "../components/FlickrGallery.astro";
|
import GrilleSpectaclesPassés from "../components/GrilleSpectaclesPassés.astro";
|
||||||
|
|
||||||
export const prerender = false
|
export const prerender = false
|
||||||
|
|
||||||
const evenements = await fetchEvenements()
|
const evenements = await fetchEvenements()
|
||||||
|
const evenementsPassés = await fetchEvenementsPassés()
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -17,24 +18,32 @@ const evenements = await fetchEvenements()
|
||||||
📌 Albi, Occitanie
|
📌 Albi, Occitanie
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Retrouvez-nous prochainement</h2>
|
{evenements.length > 0 && (
|
||||||
<div class="dates">
|
<>
|
||||||
<div class="evenements">
|
<h2>Retrouvez-nous prochainement</h2>
|
||||||
{evenements.map(evenement => (
|
<div class="dates">
|
||||||
<Evenement evenement={evenement} />
|
<div class="evenements">
|
||||||
))}
|
{evenements.map(evenement => (
|
||||||
</div>
|
<Evenement evenement={evenement} />
|
||||||
</div>
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
<h2>Nos derniers spectacles</h2>
|
{evenementsPassés.length > 0 && (
|
||||||
<FlickrGallery />
|
<>
|
||||||
|
<h2>Nos spectacles passés</h2>
|
||||||
|
<GrilleSpectaclesPassés evenements={evenementsPassés} limite={6} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
<ul role="list" class="link-card-grid">
|
<ul role="list" class="link-card-grid">
|
||||||
<Card
|
<Card
|
||||||
title="Les Particules Fines"
|
title="Les Particules Fines"
|
||||||
href="/fines"
|
href="/fines"
|
||||||
>
|
>
|
||||||
Cours d’impro adultes débutant·e·s
|
Cours d'impro adultes débutant·e·s
|
||||||
</Card>
|
</Card>
|
||||||
<Card
|
<Card
|
||||||
href="./inscription-newsletter"
|
href="./inscription-newsletter"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue