Unverified Commit fd0f4c1c by Paul-Louis NECH Committed by GitHub

Merge pull request #5 from PLNech/feat/cosmicfest-updates

feat(cosmicfest): Integrate audio players and enhance UI/UX
parents 932f76c6 cee4f024
import Head from 'next/head';
import Image from 'next/image'; // Using Next.js Image component for optimization
import { useState, useEffect } from 'react'; // Added useState and useEffect
import styles from '../../styles/cosmicfest.module.css';
import Countdown from '../../components/cosmicfest/Countdown';
// import ParVaguesFooter from '../../components/ParVaguesFooter'; // Optional: if you want to reuse the main site footer
......@@ -18,6 +19,41 @@ const getNextJune21st = () => {
export default function CosmicFestHome() {
const nextFestivalDate = getNextJune21st();
const [isModalOpen, setIsModalOpen] = useState(false);
const [modalImageSrc, setModalImageSrc] = useState('');
const [modalImageAlt, setModalImageAlt] = useState('');
const openModal = (src, alt) => {
setModalImageSrc(src);
setModalImageAlt(alt);
setIsModalOpen(true);
document.body.style.overflow = 'hidden'; // Prevent background scrolling
};
const closeModal = () => {
setIsModalOpen(false);
setModalImageSrc('');
setModalImageAlt('');
document.body.style.overflow = 'auto'; // Restore background scrolling
};
useEffect(() => {
const handleEsc = (event) => {
if (event.key === 'Escape' && isModalOpen) {
closeModal();
}
};
window.addEventListener('keydown', handleEsc);
// Cleanup function to remove listener
return () => {
window.removeEventListener('keydown', handleEsc);
// Ensure body overflow is reset if component unmounts while modal is open
if (isModalOpen) {
document.body.style.overflow = 'auto';
}
};
}, [isModalOpen]); // Dependency array includes isModalOpen
const lineup2024 = [
{ artist: "Hugo", description: "live guitare, compos et reprises", emojis:"🎸🎙️" },
......@@ -72,9 +108,9 @@ export default function CosmicFestHome() {
<div className={styles.grid}>
{lineup2024.map((item, index) => (
<div key={index} className={styles.card}>
<h3>{item.artist}</h3>
<p>{item.description}</p><br/>
<p>~ {item.emojis} ~</p>
<h3>{item.artist} <span className={styles.cardEmojis}>~ {item.emojis} ~</span></h3>
<p>{item.description}</p>
{/* The emoji line is now part of the h3, the extra <p> for emojis and <br/> are removed */}
</div>
))}
</div>
......@@ -86,10 +122,17 @@ export default function CosmicFestHome() {
<h3>photos v0</h3>
<div className={styles.gallery}>
{v0_content.photos.map((photo, index) => (
<div key={index} style={{backgroundImage: `url(${photo.src})`, backgroundSize: 'cover', backgroundPosition: 'center', height: '150px'}}>
{/* <Image src={photo.src} alt={photo.alt} width={200} height={150} objectFit="cover" /> */}
{/* Using div with background for now, as next/image needs actual image dimensions for non-fill */}
<span style={{color: '#fff', backgroundColor: 'rgba(0,0,0,0.5)', padding: '2px'}}>{photo.alt}</span>
<div
key={photo.src} // Using src as key for stability if array order changes but src is unique
className={`${styles.galleryItem} ${styles.galleryPhotoItem}`} // Ensure both classes are applied
style={{backgroundImage: `url(${photo.src})`}}
onClick={() => openModal(photo.src, photo.alt)}
role="button"
tabIndex={0}
onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); openModal(photo.src, photo.alt); } }}
aria-label={`View image: ${photo.alt}`}
>
<span>{photo.alt}</span>
</div>
))}
</div>
......@@ -106,11 +149,17 @@ export default function CosmicFestHome() {
)}
{/* Other videos */}
{v0_content.videos.map((video, index) => (
<div key={index} style={{backgroundImage: `url(${video.src})`, backgroundSize: 'cover', backgroundPosition: 'center', height: '150px'}}>
<a href={`https://www.youtube.com/watch?v=${video.id}`} target="_blank" rel="noopener noreferrer">
{video.title}
</a>
</div>
<a
key={index}
href={`https://www.youtube.com/watch?v=${video.id}`}
target="_blank"
rel="noopener noreferrer"
className={`${styles.galleryItem} ${styles.galleryVideoLink}`}
style={video.src ? {backgroundImage: `url(${video.src})`} : {}} // Apply BG only if src exists
aria-label={`Watch video: ${video.title}`}
>
<span>{video.title}</span> {/* Span for styling the text overlay */}
</a>
))}
</div>
......@@ -120,6 +169,19 @@ export default function CosmicFestHome() {
<li key={index}>{artist}</li>
))}
</ul>
<h3 style={{marginTop: '2rem'}}>audio ~ ParVagues</h3>
<p>
ecoute chaque piste ~ ecoute le set entier ~ telecharge le tout
</p>
<div className={styles.audioPlayersContainer}>
<div className={`${styles.audioEmbed} ${styles.bandcampPlayer}`}>
<iframe title="Bandcamp player for Parvagues live at Cosmicfest" style={{border: 0, width: "100%", maxWidth: "350px", height: "470px"}} src="https://bandcamp.com/EmbeddedPlayer/album=644862623/size=large/bgcol=333333/linkcol=0f91ff/tracklist=true/artwork=small/transparent=true/" seamless><a href="https://parvagues.bandcamp.com/album/live-cosmicfest">live@cosmicfest by ParVagues</a></iframe>
</div>
<div className={`${styles.audioEmbed} ${styles.soundcloudPlayer}`}>
<iframe title="Soundcloud player for Parvagues live at Cosmicfest" width="450" height="450" scrolling="no" frameBorder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/2121089043&color=%233e00f7&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true&visual=true"></iframe><div style={{fontSize: "10px", color: "#cccccc",lineBreak: "anywhere",wordBreak: "normal",overflow: "hidden",whiteSpace: "nowrap",textOverflow: "ellipsis", fontFamily: "Interstate,Lucida Grande,Lucida Sans Unicode,Lucida Sans,Garuda,Verdana,Tahoma,sans-serif",fontWeight: "100"}}><a href="https://soundcloud.com/parvagues" title="ParVagues" target="_blank" rel="noopener noreferrer" style={{color: "#cccccc", textDecoration: "none"}}>ParVagues</a> · <a href="https://soundcloud.com/parvagues/cosmicfest" title="Live@cosmicfest 🌊🌅" target="_blank" rel="noopener noreferrer" style={{color: "#cccccc", textDecoration: "none"}}>Live@cosmicfest 🌊🌅</a></div>
</div>
</div>
</section>
<section className={styles.section} id="next-edition">
......@@ -128,9 +190,12 @@ export default function CosmicFestHome() {
<Countdown targetDate={nextFestivalDate.toISOString()} />
</div>
<div style={{textAlign: 'center', marginTop: '2rem'}}>
<button className={styles.ctaButton} onClick={() => alert('waitlist bientôt disponible!')}>
prends la prochaine vague
</button>
<a
href="mailto:cosmic@nech.pl?subject=je%20suis%20cosmic%20car...&body=voila%20mon%20cot%C3%A9%20cosmique%20%3A%20..."
className={styles.ctaButton}
>
prends la prochaine vague
</a>
<p className={styles.waitlistMessage}>
pas de billetterie - cosmicfest c'est sur invitation. <br/>
riders, come to the storm.
......@@ -148,6 +213,23 @@ export default function CosmicFestHome() {
</main>
{isModalOpen && (
<div className={styles.modalOverlay} onClick={closeModal} role="dialog" aria-modal="true" aria-label={modalImageAlt || 'Image viewer'}>
<div className={styles.modalContent} onClick={(e) => e.stopPropagation()}>
<button className={styles.modalCloseButton} onClick={closeModal} aria-label="Close image viewer">
&times;
</button>
{/* For Next/Image, provide intrinsic image width/height if known, or use layout fill with sized parent.
Using layout="responsive" with some default aspect ratio here.
Actual display size will be controlled by CSS for modalImage container. */}
<div className={styles.modalImageContainer}>
<Image src={modalImageSrc} alt={modalImageAlt} layout="intrinsic" width={1200} height={900} objectFit="contain" />
</div>
{modalImageAlt && <p className={styles.modalCaption}>{modalImageAlt}</p>}
</div>
</div>
)}
<footer className={styles.footer}>
<a
href="/parvagues/"
......
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