feat(parvagues): Comprehensive UI/UX enhancements for ParVagues subsite

This commit implements a series of improvements to the ParVagues subsite, addressing issues related to layout, interactivity, and content presentation.

Key changes include:

1.  **Header Redesign:**
    *   Implemented a thinner, single-row fixed header.
    *   Logo positioned top-left, navigation links centered, and "Book" button top-right.
    *   Dynamic title now appears next to the logo on scroll or non-home pages.

2.  **Interactive Section ("Potentiel/Composition/Performance"):**
    *   Added a pointer cursor for section selection.
    *   The active section is now clearly highlighted.
    *   Implemented auto-toggling between sections every 5 seconds, with timer reset on manual click.

3.  **Album Link Sorting:**
    *   Platform links for albums in the "Sorties" section are now consistently ordered: YouTube > Deezer > Spotify > Apple Music > Tidal > Amazon.

4.  **Upcoming Events ("Prochains Événements"):**
    *   Events are now sorted by increasing date (soonest first).
    *   Card styling was reviewed and confirmed to be appropriate.

5.  **Event Page Restructure:**
    *   Improved typography: Event title is H1, countdown timer is a prominent H2, and location is H3.
    *   Enhanced above-the-fold visibility of key event information and teasers.
    *   Revamped image gallery:
        *   Displays all images as fixed-size cards in a masonry layout.
        *   Images open in a modal view on click, with a close button and Esc key dismissal.
        *   Transparent images (PNGs) now have a light background for better visibility in cards and modal.

6.  **Footer Fix:**
    *   Resolved issue where footer content (especially links) could be hidden.
    *   Removed `overflow: hidden` from the footer and adjusted its internal layout (logo size, column structure) to ensure all content is visible.
    *   Confirmed main page flexbox structure correctly pushes the footer to the bottom of the viewport.

These changes collectively improve the visual appeal, usability, and information hierarchy of the ParVagues subsite.
parent 998a6768
// next/components/ImageGallery.js // next/components/ImageGallery.js
import { useState } from 'react'; import { useState, useEffect } from 'react'; // Added useEffect
import Image from 'next/image'; import Image from 'next/image';
import Masonry from 'react-masonry-css'; import Masonry from 'react-masonry-css';
import styles from '@/styles/parvagues.module.css'; // Import css modules
export default function ImageGallery({ images, slug }) { export default function ImageGallery({ images, slug }) {
const [selectedImage, setSelectedImage] = useState(null); const [selectedImage, setSelectedImage] = useState(null);
// Close modal on Escape key press
useEffect(() => {
const handleEsc = (event) => {
if (event.key === 'Escape') {
setSelectedImage(null);
}
};
if (selectedImage) {
window.addEventListener('keydown', handleEsc);
}
return () => {
window.removeEventListener('keydown', handleEsc);
};
}, [selectedImage]);
const breakpointColumns = { const breakpointColumns = {
default: 3, default: 4, // Changed to 4 for a denser grid
1024: 3,
768: 2, 768: 2,
480: 1 480: 1,
}; };
const isPng = (src) => typeof src === 'string' && src.toLowerCase().endsWith('.png');
return ( return (
<> <>
<div className="mt-8"> <div className="mt-8">
<h3 className="text-xl font-semibold mb-4 text-purple-400">Galerie</h3> <h3 className="text-2xl font-bold mb-6 text-purple-300 text-center">Galerie Photos</h3>
<Masonry <Masonry
breakpointCols={breakpointColumns} breakpointCols={breakpointColumns}
className="masonry-grid" // Ensure this class or its child provides relative positioning for 'fill' className={styles.galleryGrid} // Use CSS module for masonry grid
columnClassName="masonry-grid_column" columnClassName={styles.galleryGridColumn}
> >
{images.map((imageSrc, i) => ( {images.map((imageSrc, i) => (
<div <div
key={i} key={i}
className="mb-4 cursor-pointer hover:opacity-75 transition-opacity" className={`${styles.galleryCard} mb-4 cursor-pointer group`}
onClick={() => setSelectedImage(imageSrc)} onClick={() => setSelectedImage(imageSrc)}
> >
{/* Ensure this div is the relatively positioned parent for fill */} <div className={`relative aspect-square rounded-lg overflow-hidden shadow-lg group-hover:shadow-xl transition-shadow duration-300 ${isPng(imageSrc) ? styles.pngBackground : 'bg-gray-800'}`}>
<div className="relative aspect-square rounded-lg overflow-hidden"> {/* Tailwind's aspect-square utility */}
<Image <Image
src={imageSrc} src={imageSrc}
alt={`${slug} image ${i + 1}`} alt={`${slug} image ${i + 1}`}
fill fill
className="object-cover" // object-cover will fill the square, cropping if necessary className={`object-cover group-hover:scale-105 transition-transform duration-300`}
/> />
</div> </div>
</div> </div>
))} ))}
</Masonry> </Masonry>
</div> </div>
{/* Lightbox */} {/* Modal */}
{selectedImage && ( {selectedImage && (
<div <div
className="fixed inset-0 z-50 bg-black/90 flex items-center justify-center cursor-zoom-out" className={styles.modalOverlay}
onClick={() => setSelectedImage(null)} onClick={() => setSelectedImage(null)}
> >
<div className="relative max-w-[90vw] max-h-[90vh]"> <div
className={`${styles.modalContent} ${isPng(selectedImage) ? styles.pngBackgroundModal : 'bg-gray-900'}`}
onClick={(e) => e.stopPropagation()} // Prevent click inside modal from closing it
>
<Image <Image
src={selectedImage} src={selectedImage}
alt="Selected image" alt="Selected image"
width={1200} // These are for the lightbox, not the gallery thumbs width={1600}
height={800} // These define the max dimensions and aspect ratio for the lightbox image height={1200}
className="max-w-full max-h-full object-contain" // object-contain is good for lightbox className="max-w-full max-h-full object-contain rounded-lg"
/> />
<button <button
className="absolute top-4 right-4 text-white text-2xl hover:text-purple-400 transition-colors" className={styles.modalCloseButton}
onClick={(e) => { onClick={() => setSelectedImage(null)}
e.stopPropagation();
setSelectedImage(null);
}}
> >
× &times; {/* Using HTML entity for '×' for better rendering */}
</button> </button>
</div> </div>
</div> </div>
......
...@@ -17,67 +17,71 @@ export default function ParVaguesFooter() { ...@@ -17,67 +17,71 @@ export default function ParVaguesFooter() {
const year = new Date().getFullYear(); const year = new Date().getFullYear();
return ( return (
<footer className="bg-black border-t border-[#d900ff]/20 py-8 relative overflow-hidden"> <footer className="bg-black border-t border-[#d900ff]/20 py-8 relative"> {/* Removed overflow-hidden */}
<div className={styles.neonGradient}></div> <div className={styles.neonGradient}></div>
<div className="max-w-6xl mx-auto px-4 relative z-10"> <div className="max-w-6xl mx-auto px-4 relative z-10">
<div className="grid grid-cols-1 md:grid-cols-2 gap-8"> <div className="grid grid-cols-1 md:grid-cols-3 gap-8 items-start"> {/* Changed to md:grid-cols-3 and items-start */}
{/* About Column */} {/* About Column */}
<div> <div className="md:col-span-1"> {/* Explicit column span */}
<p className="text-gray-400 text-sm mb-4"> <p className="text-gray-400 text-sm mb-4">
Livecoding de musique libre<br /> Livecoding de musique libre<br />
Performances algorithmiques en direct. Performances algorithmiques en direct.
</p> </p>
<p className="text-xs text-gray-500">
&copy; {year} ParVagues. Tous droits réservés.
</p>
</div> </div>
{/* Social Column */} {/* Logo Column (New) */}
<div className="flex flex-col items-center md:items-end"> <div className="md:col-span-1 flex flex-col items-center justify-center"> {/* Centering logo */}
<div className="flex justify-center w-full"> <div className="relative mb-4">
<div className="relative"> <Image
<Image src="/images/parvagues/logo.png"
src="/images/parvagues/logo.png" alt="ParVagues Logo"
alt="ParVagues Logo" width={100} // Reduced logo size
width={240} height={100} // Reduced logo size
height={240} />
className="mx-auto mb-4"
/>
</div>
</div> </div>
</div>
<div className="flex flex-wrap gap-4 justify-center md:justify-end"> {/* Social Column */}
<div className="md:col-span-1 flex flex-col items-center md:items-end"> {/* Explicit column span */}
<p className="text-gray-400 text-sm mb-3 text-center md:text-right">Restons connectés :</p>
<div className="flex flex-wrap gap-3 justify-center md:justify-end"> {/* Reduced gap */}
{socialLinks.map((link, index) => ( {socialLinks.map((link, index) => (
<a <a
key={index} key={index}
href={link.url} href={link.url}
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
className="bg-gray-800 hover:bg-[#8900b3]/60 text-white p-3 rounded-full transition-colors shadow-md hover:shadow-[#d900ff]/40" className="bg-gray-800 hover:bg-purple-700/70 text-white p-2.5 rounded-full transition-colors shadow-md hover:shadow-purple-500/40" // Slightly smaller padding
aria-label={link.label} aria-label={link.label}
> >
{link.icon} {React.cloneElement(link.icon, { size: '1.1em' })} {/* Slightly smaller icons */}
</a> </a>
))} ))}
</div> </div>
</div> </div>
</div> </div>
{/* Navigation Links - more compact */} {/* Navigation Links - more compact and centered */}
<div className="w-full bg-black py-4"> <div className="w-full mt-8 pt-6 border-t border-purple-500/10"> {/* Added top margin, padding and border */}
<div className="flex justify-center items-center space-x-8 text-xs tracking-widest uppercase flex-wrap"> <div className="flex justify-center items-center space-x-6 text-xs tracking-wider uppercase flex-wrap gap-y-2"> {/* Reduced space-x, added gap-y */}
<Link href="/parvagues#music" className="text-gray-300 hover:text-[#ff3d7b] transition-colors tracking-wider px-3"> <Link href="/parvagues#music" className="text-gray-400 hover:text-purple-400 transition-colors px-2">
MUSIQUE Musique
</Link> </Link>
<Link href="/parvagues#performances" className="text-gray-300 hover:text-[#ff3d7b] transition-colors tracking-wider px-3"> <Link href="/parvagues#performances" className="text-gray-400 hover:text-purple-400 transition-colors px-2">
PERFORMANCES Performances
</Link> </Link>
<Link href="/parvagues#about" className="text-gray-300 hover:text-[#ff3d7b] transition-colors tracking-wider px-3"> <Link href="/parvagues#about" className="text-gray-400 hover:text-purple-400 transition-colors px-2">
À PROPOS À Propos
</Link> </Link>
<a <a
href="mailto:parvagues@nech.pl?subject=Booking Request" href="mailto:parvagues@nech.pl?subject=Booking Request"
className="text-gray-300 hover:text-[#ff3d7b] transition-colors tracking-wider px-3" className="text-gray-400 hover:text-purple-400 transition-colors px-2"
> >
RÉSERVER Réserver
</a> </a>
</div> </div>
</div> </div>
...@@ -85,4 +89,4 @@ export default function ParVaguesFooter() { ...@@ -85,4 +89,4 @@ export default function ParVaguesFooter() {
</div> </div>
</footer> </footer>
); );
} }
\ No newline at end of file \ No newline at end of file
...@@ -27,66 +27,60 @@ function useScrolledPast(threshold = 100) { ...@@ -27,66 +27,60 @@ function useScrolledPast(threshold = 100) {
export default function ParVaguesHeader({ eventName = null, title = null }) { export default function ParVaguesHeader({ eventName = null, title = null }) {
const router = useRouter(); const router = useRouter();
const isHome = router.pathname === '/parvagues'; const isHome = router.pathname === '/parvagues';
const showInHeader = useScrolledPast(300); const showInHeader = useScrolledPast(300); // Threshold for showing title on scroll
const headerTitle = title || eventName || 'ParVagues'; const headerTitle = title || eventName || 'ParVagues';
return ( return (
<header className="sticky top-0 left-0 w-full z-50 bg-black/80 backdrop-blur-md border-b border-[#d900ff]/20"> <header className={`sticky top-0 left-0 w-full z-50 bg-black/80 backdrop-blur-md border-b border-[#d900ff]/20 ${styles.headerContainer}`}>
<div className={`${styles.neonGradient} opacity-5 absolute inset-0`}></div> <div className={`${styles.neonGradient} opacity-5 absolute inset-0`}></div>
<div className="max-w-6xl mx-auto px-4 py-3 flex items-center justify-between"> <div className="max-w-full mx-auto px-4 flex items-center justify-between h-16"> {/* Reduced height here, e.g. h-16 for 4rem */}
{/* Logo and Title with Navigation */} {/* Logo and Title */}
<div className="flex items-center justify-between w-full"> <Link href="/parvagues" className="flex items-center group">
<Link href="/parvagues" className="flex items-center group"> <div className="h-10 w-10 relative flex-shrink-0"> {/* Ensure logo size is controlled */}
<div className="h-10 w-10 relative flex-shrink-0"> <Image
<Image src="/images/parvagues/logo.png"
src="/images/parvagues/logo.png" alt="ParVagues Logo"
alt="ParVagues Logo" width={40} // Adjusted size
width={48} height={40} // Adjusted size
height={48} className="object-contain transition-all duration-300 group-hover:filter group-hover:drop-shadow-[0_0_8px_rgba(217,0,255,0.7)]"
className="object-contain transition-all duration-300 group-hover:filter group-hover:drop-shadow-[0_0_8px_rgba(217,0,255,0.7)]" />
/> </div>
</div> <div className="overflow-hidden ml-3"> {/* Increased margin slightly */}
<span
<div className="overflow-hidden ml-2"> className={`text-white font-bold transition-all duration-500 ${
<span showInHeader || !isHome ? 'opacity-100 translate-y-0' : 'opacity-0 -translate-y-full' // Adjusted animation
className={`text-white font-bold transition-all duration-500 ${ }`}
showInHeader || !isHome ? 'opacity-100 translate-y-0' : 'opacity-0 -translate-y-8' style={{
}`} textShadow: '0 0 5px rgba(217, 0, 255, 0.7), 0 0 10px rgba(217, 0, 255, 0.5)',
style={{ color: 'var(--neon-high)'
textShadow: '0 0 5px rgba(217, 0, 255, 0.7), 0 0 10px rgba(217, 0, 255, 0.5)', }}
color: 'var(--neon-high)'
}}
>
{headerTitle}
</span>
</div>
</Link>
{/* Navigation and CTA */}
<div className="flex items-center space-x-6">
{/* Navigation Links */}
<nav className="flex items-center space-x-6 text-sm tracking-wider">
<Link href="/parvagues#music" className="text-gray-300 hover:text-[#ff3d7b] transition-colors">
Music
</Link>
<Link href="/parvagues#performances" className="text-gray-300 hover:text-[#ff3d7b] transition-colors">
Performances
</Link>
<Link href="/parvagues#about" className="text-gray-300 hover:text-[#ff3d7b] transition-colors">
About
</Link>
</nav>
{/* CTA button */}
<Link
href="/book"
className={`${styles.outlineButton} py-2 px-4 text-sm flex items-center whitespace-nowrap`}
> >
<FaEnvelope className="mr-2 flex-shrink-0" /> {headerTitle}
<span>Book</span> </span>
</Link>
</div> </div>
</div> </Link>
{/* Navigation Links */}
<nav className="flex-grow flex justify-center items-center space-x-6 text-sm tracking-wider">
<Link href="/parvagues#music" className={`${styles.navLink} text-gray-300 hover:text-[#ff3d7b] transition-colors`}>
Music
</Link>
<Link href="/parvagues#performances" className={`${styles.navLink} text-gray-300 hover:text-[#ff3d7b] transition-colors`}>
Performances
</Link>
<Link href="/parvagues#about" className={`${styles.navLink} text-gray-300 hover:text-[#ff3d7b] transition-colors`}>
About
</Link>
</nav>
{/* CTA button */}
<Link
href="/book"
className={`${styles.outlineButton} ${styles.bookButton} py-2 px-4 text-sm flex items-center whitespace-nowrap`} // Added custom class for specific styling if needed
>
<FaEnvelope className="mr-2 flex-shrink-0" />
<span>Book</span>
</Link>
</div> </div>
</header> </header>
); );
......
...@@ -67,10 +67,10 @@ export default function ParVagues({ lives }) { ...@@ -67,10 +67,10 @@ export default function ParVagues({ lives }) {
const backgroundRef = useRef(null); const backgroundRef = useRef(null);
const audioRef = useRef(null); const audioRef = useRef(null);
// Filter future events // Filter future events and sort them by date in ascending order
const futureEvents = lives.filter(live => { const futureEvents = lives.filter(live => {
return new Date(live.date) > new Date(); return new Date(live.date) > new Date();
}); }).sort((a, b) => new Date(a.date) - new Date(b.date));
// Define section content // Define section content
const sections = { const sections = {
...@@ -119,6 +119,20 @@ d4 $ note ("<e3 fs3 <gs3 d4> <a3 df4>>" - 12) ...@@ -119,6 +119,20 @@ d4 $ note ("<e3 fs3 <gs3 d4> <a3 df4>>" - 12)
setCurrentImageIndex(0); setCurrentImageIndex(0);
} }
}, [selectedSection]); }, [selectedSection]);
// Auto-toggling for sections (Potentiel, Composition, Performance)
const sectionOrder = ['potentiel', 'composition', 'performance'];
useEffect(() => {
const intervalId = setInterval(() => {
setSelectedSection(currentSection => {
const currentIndex = sectionOrder.indexOf(currentSection);
const nextIndex = (currentIndex + 1) % sectionOrder.length;
return sectionOrder[nextIndex];
});
}, 5000); // 5 seconds
return () => clearInterval(intervalId); // Cleanup on component unmount or when selectedSection changes
}, [selectedSection]); // Re-run effect (and reset timer) when selectedSection changes
// Auto-advance carousel for section images // Auto-advance carousel for section images
useEffect(() => { useEffect(() => {
...@@ -176,7 +190,10 @@ d4 $ note ("<e3 fs3 <gs3 d4> <a3 df4>>" - 12) ...@@ -176,7 +190,10 @@ d4 $ note ("<e3 fs3 <gs3 d4> <a3 df4>>" - 12)
} }
}; };
const albums = [ // Define the desired order of platforms
const platformOrder = ['YouTube', 'Deezer', 'Spotify', 'Apple', 'Tidal', 'Amazon'];
const albumsData = [
{ {
id: '2024_opal', id: '2024_opal',
title: 'Livecoding (Opal Festival 2024)', title: 'Livecoding (Opal Festival 2024)',
...@@ -203,6 +220,19 @@ d4 $ note ("<e3 fs3 <gs3 d4> <a3 df4>>" - 12) ...@@ -203,6 +220,19 @@ d4 $ note ("<e3 fs3 <gs3 d4> <a3 df4>>" - 12)
] ]
} }
]; ];
// Sort the links for each album
const albums = albumsData.map(album => ({
...album,
links: album.links.sort((a, b) => {
const indexA = platformOrder.indexOf(a.platform);
const indexB = platformOrder.indexOf(b.platform);
// If a platform is not in platformOrder, keep its relative order towards the end
if (indexA === -1) return 1;
if (indexB === -1) return -1;
return indexA - indexB;
})
}));
const renderSectionContent = () => { const renderSectionContent = () => {
const sectionContent = sections[selectedSection]; const sectionContent = sections[selectedSection];
...@@ -343,40 +373,40 @@ d4 $ note ("<e3 fs3 <gs3 d4> <a3 df4>>" - 12) ...@@ -343,40 +373,40 @@ d4 $ note ("<e3 fs3 <gs3 d4> <a3 df4>>" - 12)
<section id="section1" className={styles.sectionContainer}> <section id="section1" className={styles.sectionContainer}>
<div className={styles.splitSection}> <div className={styles.splitSection}>
<div> <div>
<div <div
className={`cursor-pointer transition-all duration-300 hover:bg-purple-500/10 rounded-lg p-2 ${selectedSection === 'potentiel' ? 'text-purple-400 border-l-2 border-purple-400 pl-4' : ''}`} className={`cursor-pointer transition-all duration-300 hover:bg-purple-500/10 rounded-lg p-2 ${selectedSection === 'potentiel' ? 'text-purple-400 border-l-2 border-purple-400 pl-4' : 'text-gray-400 border-l-2 border-transparent'}`}
onClick={() => setSelectedSection('potentiel')} onClick={() => setSelectedSection('potentiel')}
> >
<h3 className={`${styles.bulletPoint} text-xl font-semibold text-purple-400 mb-2 group relative inline-block`} style={{ margin: '1em 0', textDecorationLine: 'underline', textDecorationColor: 'darkviolet', textDecorationThickness: '3px' }}> <h3 className={`${styles.bulletPoint} text-xl font-semibold mb-2 group relative inline-block ${selectedSection === 'potentiel' ? 'text-purple-400' : 'text-gray-400'}`} style={{ margin: '1em 0', textDecorationLine: 'underline', textDecorationColor: 'darkviolet', textDecorationThickness: '3px' }}>
Potentiel Potentiel
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-gradient-to-r from-purple-400 to-pink-500 group-hover:w-full transition-all duration-300"></span> <span className="absolute bottom-0 left-0 w-0 h-0.5 bg-gradient-to-r from-purple-400 to-pink-500 group-hover:w-full transition-all duration-300"></span>
</h3> </h3>
<p className="text-gray-300">Samples glanés et synthés SuperCollider</p> <p className={`${selectedSection === 'potentiel' ? 'text-gray-300' : 'text-gray-500'}`}>Samples glanés et synthés SuperCollider</p>
</div> </div>
<div <div
className={`cursor-pointer transition-all duration-300 hover:bg-purple-500/10 rounded-lg p-2 ${selectedSection === 'composition' ? 'text-purple-400 border-l-2 border-purple-400 pl-4' : ''}`} className={`cursor-pointer transition-all duration-300 hover:bg-purple-500/10 rounded-lg p-2 ${selectedSection === 'composition' ? 'text-purple-400 border-l-2 border-purple-400 pl-4' : 'text-gray-400 border-l-2 border-transparent'}`}
onClick={() => setSelectedSection('composition')} onClick={() => setSelectedSection('composition')}
> >
<h3 className={`${styles.bulletPoint} text-xl font-semibold text-purple-400 mb-2 group relative inline-block`} style={{ margin: '1em 0', textDecorationLine: 'underline', textDecorationColor: 'darkviolet', textDecorationThickness: '3px' }}> <h3 className={`${styles.bulletPoint} text-xl font-semibold mb-2 group relative inline-block ${selectedSection === 'composition' ? 'text-purple-400' : 'text-gray-400'}`} style={{ margin: '1em 0', textDecorationLine: 'underline', textDecorationColor: 'darkviolet', textDecorationThickness: '3px' }}>
Composition Composition
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-gradient-to-r from-purple-400 to-pink-500 group-hover:w-full transition-all duration-300"></span> <span className="absolute bottom-0 left-0 w-0 h-0.5 bg-gradient-to-r from-purple-400 to-pink-500 group-hover:w-full transition-all duration-300"></span>
</h3> </h3>
<p className="text-gray-300">Code Haskell TidalCycles + input MIDI</p> <p className={`${selectedSection === 'composition' ? 'text-gray-300' : 'text-gray-500'}`}>Code Haskell TidalCycles + input MIDI</p>
</div> </div>
<div <div
className={`cursor-pointer transition-all duration-300 hover:bg-purple-500/10 rounded-lg p-2 ${selectedSection === 'performance' ? 'text-purple-400 border-l-2 border-purple-400 pl-4' : ''}`} className={`cursor-pointer transition-all duration-300 hover:bg-purple-500/10 rounded-lg p-2 ${selectedSection === 'performance' ? 'text-purple-400 border-l-2 border-purple-400 pl-4' : 'text-gray-400 border-l-2 border-transparent'}`}
onClick={() => setSelectedSection('performance')} onClick={() => setSelectedSection('performance')}
> >
<h3 className={`${styles.bulletPoint} text-xl font-semibold text-purple-400 mb-2 group relative inline-block`} style={{ margin: '1em 0', textDecorationLine: 'underline', textDecorationColor: 'darkviolet', textDecorationThickness: '3px' }}> <h3 className={`${styles.bulletPoint} text-xl font-semibold mb-2 group relative inline-block ${selectedSection === 'performance' ? 'text-purple-400' : 'text-gray-400'}`} style={{ margin: '1em 0', textDecorationLine: 'underline', textDecorationColor: 'darkviolet', textDecorationThickness: '3px' }}>
Performance Performance
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-gradient-to-r from-purple-400 to-pink-500 group-hover:w-full transition-all duration-300"></span> <span className="absolute bottom-0 left-0 w-0 h-0.5 bg-gradient-to-r from-purple-400 to-pink-500 group-hover:w-full transition-all duration-300"></span>
</h3> </h3>
<p className="text-gray-300">Performance live avec improvisation au contrôleur MIDI</p> <p className={`${selectedSection === 'performance' ? 'text-gray-300' : 'text-gray-500'}`}>Performance live avec improvisation au contrôleur MIDI</p>
</div> </div>
</div> </div>
<div> <div>
{renderSectionContent()} {renderSectionContent()}
</div> </div>
......
...@@ -562,5 +562,100 @@ AS MODULE CSS FORBIDS ROOT VARIABLES ...@@ -562,5 +562,100 @@ AS MODULE CSS FORBIDS ROOT VARIABLES
} }
img.live-gallery-image { img.live-gallery-image {
max-width: 1em; width: 100%;
height: 100%;
object-fit: cover;
}
/* Image Gallery Styles */
.galleryGrid {
display: flex;
margin-left: -1rem; /* gutter size offset */
width: auto;
}
.galleryGridColumn {
padding-left: 1rem; /* gutter size */
background-clip: padding-box;
}
.galleryCard {
/* Base card styling if needed beyond Tailwind */
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.galleryCard:hover {
transform: translateY(-5px);
}
.pngBackground {
background-color: #e9e9e9; /* Light gray background for PNG cards */
}
.pngBackgroundModal {
background-color: #cccccc; /* Slightly darker gray for modal PNG background for contrast */
}
.modalOverlay {
position: fixed;
inset: 0;
background-color: rgba(0, 0, 0, 0.85);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000; /* High z-index */
padding: 1rem;
}
.modalContent {
position: relative;
padding: 1rem; /* Padding around the image in modal */
border-radius: 0.5rem; /* Rounded corners for the modal content box */
max-width: 95vw;
max-height: 95vh;
display: flex; /* Allow image to determine size up to max */
align-items: center;
justify-content: center;
}
.modalCloseButton {
position: absolute;
top: -10px; /* Position outside the content padding */
right: -5px;
background: rgba(30, 30, 30, 0.8);
color: white;
border: none;
border-radius: 50%;
width: 30px;
height: 30px;
font-size: 1.5rem;
line-height: 28px; /* Vertically center times symbol */
text-align: center;
cursor: pointer;
transition: background-color 0.2s ease, color 0.2s ease;
box-shadow: 0 2px 10px rgba(0,0,0,0.5);
}
.modalCloseButton:hover {
background-color: var(--neon-high); /* Use theme color */
color: black;
}
/* Styles for the updated ParVaguesHeader */
.headerContainer {
/* Ensuring vertical alignment for items if needed, though Tailwind's `items-center` on the child div should handle this. */
/* Example: display: flex; align-items: center; */
/* Height is controlled by Tailwind's h-16 class in the component */
}
.navLink {
/* Individual styling for nav links if required beyond Tailwind classes */
/* Example: padding: 0.5rem 1rem; */
/* The space-x-6 on the parent nav element in JSX handles spacing between links */
}
.bookButton {
/* Specific adjustments for the book button if necessary */
/* Example: ensure it aligns well with the new header height */
/* padding-top: 0.5rem; padding-bottom: 0.5rem; /* Adjust if default py-2 is too large */
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment