Commit 33f858b7 by PLN (Algolia)

feat(parvagues): Title++

parent fc9f96aa
import { useState, useEffect, useRef } from 'react';
export default function GlitchText({ text, className, burstFrequency = 30000 }) {
const [displayText, setDisplayText] = useState(text);
const [isBursting, setIsBursting] = useState(false);
const burstTimeoutRef = useRef(null);
const glitchIntervalRef = useRef(null);
// Collection of diacritical marks to add to characters
const diacritics = [
'\u0301', // Acute accent
'\u0300', // Grave accent
'\u0308', // Diaeresis
'\u0303', // Tilde
'\u0327', // Cedilla
'\u0306', // Breve
'\u0304', // Macron
'\u0302', // Circumflex
'\u030C', // Caron
'\u0307', // Dot above
'\u0328', // Ogonek
'\u0323', // Dot below
'\u0331', // Macron below
'\u0337', // Short overlay
];
// More intense effects for burst mode
const cursedCombiningMarks = [
'\u035C', // Double breve below
'\u035F', // Combining double macron below
'\u0360', // Combining double tilde
'\u0361', // Combining double inverted breve
'\u0362', // Combining double rightwards arrow below
'\u0489', // Combining cyrillic millions sign
'\u036F', // Combining latin small letter x
'\u033E', // Combining vertical tilde
'\u035D', // Combining double breve
'\u0346', // Combining bridge above
'\u031A', // Combining left angle above
'\u0359', // Combining asterisk below
];
const applyRandomDiacritic = (char) => {
// Don't apply diacritics to spaces
if (char === ' ') return char;
const shouldAddDiacritic = Math.random() < (isBursting ? 0.8 : 0.1);
if (!shouldAddDiacritic) return char;
// During bursts, possibly apply multiple diacritics
if (isBursting && Math.random() < 0.4) {
const numMarks = Math.floor(Math.random() * 3) + 1;
let result = char;
const allMarks = [...diacritics, ...cursedCombiningMarks];
for (let i = 0; i < numMarks; i++) {
const mark = allMarks[Math.floor(Math.random() * allMarks.length)];
result += mark;
}
return result;
}
// Normal mode - just add a single diacritic
const diacritic = diacritics[Math.floor(Math.random() * diacritics.length)];
return char + diacritic;
};
const glitchText = () => {
const glitchIntensity = isBursting ? 0.8 : 0.05;
// Apply glitch to the text
const glitchedText = Array.from(text).map(char => {
// Chance to apply a diacritic
if (Math.random() < glitchIntensity) {
return applyRandomDiacritic(char);
}
return char;
}).join('');
setDisplayText(glitchedText);
};
const startBurst = () => {
setIsBursting(true);
// Clear any existing interval
if (glitchIntervalRef.current) {
clearInterval(glitchIntervalRef.current);
}
// Create a faster interval during burst
glitchIntervalRef.current = setInterval(glitchText, 100);
// End burst after 1-2 seconds
setTimeout(() => {
setIsBursting(false);
clearInterval(glitchIntervalRef.current);
glitchIntervalRef.current = setInterval(glitchText, 2000);
}, 1000 + Math.random() * 1000);
};
// Setup effect - runs when component mounts or when burstFrequency changes
useEffect(() => {
// Clean up any existing intervals and timeouts
if (glitchIntervalRef.current) {
clearInterval(glitchIntervalRef.current);
}
if (burstTimeoutRef.current) {
clearTimeout(burstTimeoutRef.current);
}
// Initial setup - slow glitch every 2 seconds
glitchIntervalRef.current = setInterval(glitchText, 2000);
// Set up random bursts
const scheduleBurst = () => {
const nextBurstTime = burstFrequency + (Math.random() * burstFrequency * 0.5);
burstTimeoutRef.current = setTimeout(() => {
startBurst();
scheduleBurst();
}, nextBurstTime);
};
// Trigger immediate glitch to show effect immediately
glitchText();
// Schedule the first burst
scheduleBurst();
// Cleanup on unmount or when dependencies change
return () => {
clearInterval(glitchIntervalRef.current);
clearTimeout(burstTimeoutRef.current);
};
}, [burstFrequency]); // Add burstFrequency as a dependency
return (
<span className={className} data-text={text}>
{displayText}
</span>
);
}
\ No newline at end of file
import React from 'react';
import Link from 'next/link';
import Image from 'next/image';
import { FaEnvelope, FaInstagram, FaTwitter } from 'react-icons/fa';
import { SiMastodon, SiBluesky } from 'react-icons/si';
import styles from '@/styles/parvagues.module.css';
......@@ -16,51 +17,54 @@ export default function ParVaguesFooter() {
const year = new Date().getFullYear();
return (
<footer className="bg-black border-t border-purple-500/20 py-12">
<div className="max-w-6xl mx-auto px-4">
<footer className="bg-black border-t border-[#d900ff]/20 py-12 relative overflow-hidden">
<div className={styles.neonGradient}></div>
<div className="max-w-6xl mx-auto px-4 relative z-10">
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
{/* About Column */}
<div>
<h3 className="text-purple-400 font-semibold text-lg mb-4">ParVagues</h3>
<div className="flex items-center mb-4">
<div className="w-12 h-12 relative mr-3">
{/* <Image
src="/images/parvagues/logo.png"
alt="ParVagues Logo"
fill
className="object-contain"
sizes="48px"
/> */}
</div>
<h3 className="text-[#d900ff] font-semibold text-lg">ParVagues</h3>
</div>
<p className="text-gray-400 text-sm mb-4">
Livecoding de musique open-source avec TidalCycles et contrôleur MIDI.
Livecoding de musique open-source avec TidalCycles et contrôleur MIDI.<br />
Performances algorithmiques et création sonore en direct.
</p>
</div>
{/* Links Column */}
<div>
<h3 className="text-purple-400 font-semibold text-lg mb-4">Explorez</h3>
<ul className="space-y-2 text-sm">
<li>
<Link href="/parvagues#music" className="text-gray-400 hover:text-purple-300 transition-colors">
Musique
</Link>
</li>
<li>
<Link href="/parvagues#performances" className="text-gray-400 hover:text-purple-300 transition-colors">
Performances
</Link>
</li>
<li>
<Link href="/parvagues#about" className="text-gray-400 hover:text-purple-300 transition-colors">
À propos
</Link>
</li>
<li>
<a
href="mailto:parvagues@nech.pl?subject=Booking Request"
className="text-gray-400 hover:text-purple-300 transition-colors"
>
Réserver un live
</a>
</li>
</ul>
{/* Navigation Links */}
<div className="w-full bg-black py-2">
<div className="max-w-6xl mx-auto flex justify-center items-center space-x-6 text-xs tracking-widest uppercase">
<Link href="/parvagues#music" className="text-gray-300 hover:text-[#ff3d7b] transition-colors">
MUSIQUE
</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">
À PROPOS
</Link>
<a
href="mailto:parvagues@nech.pl?subject=Booking Request"
className="text-gray-300 hover:text-[#ff3d7b] transition-colors"
>
RÉSERVER UN LIVE
</a>
</div>
</div>
{/* Social Column */}
<div>
<h3 className="text-purple-400 font-semibold text-lg mb-4">Connect</h3>
<h3 className="text-[#d900ff] font-semibold text-lg mb-4">Connect</h3>
<div className="flex flex-wrap gap-4">
{socialLinks.map((link, index) => (
<a
......@@ -68,7 +72,7 @@ export default function ParVaguesFooter() {
href={link.url}
target="_blank"
rel="noopener noreferrer"
className="bg-gray-800 hover:bg-purple-900 text-white p-3 rounded-full transition-colors"
className="bg-gray-800 hover:bg-[#8900b3]/60 text-white p-3 rounded-full transition-colors shadow-md hover:shadow-[#d900ff]/40"
aria-label={link.label}
>
{link.icon}
......
import React, { useState, useEffect } from 'react';
import React from 'react';
import Link from 'next/link';
import Image from 'next/image';
import { FaEnvelope } from 'react-icons/fa';
import styles from '@/styles/parvagues.module.css';
export default function ParVaguesHeader({ eventName = null }) {
const [scrolled, setScrolled] = useState(false);
useEffect(() => {
const handleScroll = () => {
setScrolled(window.scrollY > window.innerHeight);
};
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
return (
<header
className="fixed top-0 left-0 w-full z-50 bg-gradient-to-b from-black/90 to-black/70 backdrop-blur-md transition-all duration-300 border-b border-purple-500/20 shadow-lg"
className="fixed top-0 left-0 w-full z-50 bg-black/80 backdrop-blur-md border-b border-[#d900ff]/20 shadow-lg"
>
<div className="max-w-6xl mx-auto px-4 py-4 flex justify-between items-center">
<div className="max-w-6xl mx-auto px-4 py-3 flex justify-between items-center">
<div className="flex items-center gap-2">
<Link href="/parvagues" className="text-purple-400 hover:text-purple-300 transition-colors">
ParVagues
<Link href="/parvagues" className="flex items-center">
<div className="w-10 h-10 relative mr-2">
<Image
src="/images/parvagues/favicon.ico"
alt="ParVagues Logo"
fill
className="object-contain"
sizes="40px"
/>
</div>
<span className="text-[#d900ff] text-xl font-bold">ParVagues</span>
</Link>
{eventName && (
<>
......@@ -36,13 +33,13 @@ export default function ParVaguesHeader({ eventName = null }) {
{/* Navigation Links */}
<div className="hidden md:flex items-center space-x-6 text-sm">
<Link href="/parvagues#music" className="text-white hover:text-purple-300 transition-colors">
<Link href="/parvagues#music" className="text-white hover:text-[#ff3d7b] transition-colors">
Music
</Link>
<Link href="/parvagues#performances" className="text-white hover:text-purple-300 transition-colors">
<Link href="/parvagues#performances" className="text-white hover:text-[#ff3d7b] transition-colors">
Performances
</Link>
<Link href="/parvagues#about" className="text-white hover:text-purple-300 transition-colors">
<Link href="/parvagues#about" className="text-white hover:text-[#ff3d7b] transition-colors">
About
</Link>
</div>
......@@ -50,10 +47,10 @@ export default function ParVaguesHeader({ eventName = null }) {
{/* CTA button */}
<a
href="mailto:parvagues@nech.pl?subject=Booking Request&body=Bonjour,%0D%0A%0D%0AJe souhaiterais discuter d'une possibilité de performance live coding."
className={`${styles.ctaButton} transition-all duration-300 ${scrolled ? 'bg-purple-600 scale-90' : ''}`}
className={styles.ctaButton}
>
<FaEnvelope className="inline mr-2" />
{scrolled ? 'Invoquer' : 'Invoquer un live'}
Invoquer un live
</a>
</div>
</header>
......
import 'bootstrap/dist/css/bootstrap.css'
import '../styles/globals.css'
import '../styles/main.css'
import '../styles/masonry.css'
......
......@@ -7,6 +7,7 @@ import styles from '@/styles/parvagues.module.css';
import dynamic from 'next/dynamic';
import ParVaguesHeader from '@/components/ParVaguesHeader';
import ParVaguesFooter from '@/components/ParVaguesFooter';
import GlitchText from '@/components/GlitchText';
import SyntaxHighlighter from "react-syntax-highlighter";
import { atomOneDark } from "react-syntax-highlighter/dist/cjs/styles/hljs";
......@@ -68,11 +69,11 @@ export default function ParVagues({ lives }) {
// Define section content
const sections = {
potentiel: {
code: {
type: 'image',
image: '/images/parvagues/samples.png'
},
composition: {
midi: {
type: 'carousel',
images: [
'/images/parvagues/studio1.jpg',
......@@ -86,10 +87,6 @@ export default function ParVagues({ lives }) {
'/images/parvagues/live.jpg',
'/images/parvagues/code_overlay.jpg'
]
},
code: {
type: 'code',
content: tidalCode
}
};
......@@ -294,6 +291,7 @@ d4 $ note ("<e3 fs3 <gs3 d4> <a3 df4>>" - 12)
<title>ParVagues - Musique Algorithmique</title>
<meta name="description" content="Livecoding de musique open-source avec TidalCycles et contrôleur MIDI" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="/images/parvagues/favicon.ico" />
</Head>
<div className="flex flex-col min-h-screen bg-black text-white">
......@@ -330,8 +328,12 @@ d4 $ note ("<e3 fs3 <gs3 d4> <a3 df4>>" - 12)
<div className={styles.heroContent}>
{/* Left side: Title and content */}
<div className="md:w-1/2">
<h1 className={`${styles.heroTitle} ${styles.glitchEffect}`}>
ParVagues
<h1 className={styles.heroTitle}>
<GlitchText
text="ParVagues"
className={styles.glitchEffect}
burstFrequency={450}
/>
</h1>
<p className={styles.heroSubtitle}>
Livecoding de musique open-source avec TidalCycles et contrôleur MIDI
......@@ -344,7 +346,7 @@ d4 $ note ("<e3 fs3 <gs3 d4> <a3 df4>>" - 12)
{/* Right side: Code sample with play overlay */}
<div className="md:w-1/2 relative">
<div className="relative">
<CodeBlock height="300px" isTerminal={true}>
<CodeBlock className="h-full" isTerminal={true}>
{tidalCode}
</CodeBlock>
......@@ -397,14 +399,6 @@ d4 $ note ("<e3 fs3 <gs3 d4> <a3 df4>>" - 12)
<h3 className="text-xl font-semibold text-purple-400 mb-2">Performance</h3>
<p className="text-gray-300">Live improvise avec contrôleur MIDI pour une interactivité totale</p>
</div>
<div
className={`${styles.bulletPoint} cursor-pointer ${selectedSection === 'code' ? 'text-purple-400 border-l-2 border-purple-400 pl-4' : ''}`}
onClick={() => setSelectedSection('code')}
>
<h3 className="text-xl font-semibold text-purple-400 mb-2">Code</h3>
<p className="text-gray-300">Voir un exemple de pattern TidalCycles en action</p>
</div>
</div>
<div>
......@@ -456,34 +450,7 @@ d4 $ note ("<e3 fs3 <gs3 d4> <a3 df4>>" - 12)
</div>
</section>
{/* Section 3: Performances */}
<section id="performances" className={styles.sectionContainer}>
<h2 className="text-3xl font-bold mb-8 text-center">
<span className="bg-gradient-to-r from-purple-400 to-pink-600 bg-clip-text text-transparent">
Performances
</span>
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{posterImages.map((src, index) => (
<div key={index} className="relative aspect-[3/4] rounded-lg overflow-hidden group">
<Image
src={src}
alt={`Performance ${index + 1}`}
fill
className="object-cover transition-transform duration-500 group-hover:scale-110"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-black/20 to-transparent opacity-60 group-hover:opacity-80 transition-opacity">
</div>
<div className="absolute bottom-0 left-0 w-full p-4 text-white">
<h3 className="text-xl font-bold mb-1">Live {2022 + Math.floor(index/2)}</h3>
<p className="text-sm opacity-80">Algorave Paris</p>
</div>
</div>
))}
</div>
</section>
{/* Section 4: About */}
{/* Section 3: About */}
<section id="about" className={`${styles.sectionContainer} pb-24`}>
<h2 className="text-3xl font-bold mb-8 text-center">
<span className="bg-gradient-to-r from-purple-400 to-pink-600 bg-clip-text text-transparent">
......
......@@ -42,7 +42,7 @@ export default function Live({ data, slug, images }) {
// Fix scroll handling for header
useEffect(() => {
const handleScroll = () => {
setScrolled(window.scrollY > 100);
setScrolled(window.scrollY > window.innerHeight);
};
// Initial check
......@@ -255,6 +255,7 @@ export default function Live({ data, slug, images }) {
<Head>
<title>{data.frontmatter.title} - ParVagues</title>
<meta name="description" content={data.frontmatter.description} />
<link rel="icon" href="/images/parvagues/favicon.ico" />
</Head>
{/* Above fold section */}
......@@ -266,11 +267,14 @@ export default function Live({ data, slug, images }) {
src={posterImage}
alt={data.frontmatter.title}
fill
className={styles.posterImage}
className={styles.posterImageBG}
/>
<div className={styles.posterGradient}></div>
</div>
)}
{/* Neon gradient overlay */}
<div className={styles.neonGradient}></div>
{/* Use the ParVaguesHeader component */}
<ParVaguesHeader eventName={data.frontmatter.title} />
......@@ -280,7 +284,7 @@ export default function Live({ data, slug, images }) {
{/* Main hero content */}
<div className="relative z-10 flex items-center justify-center min-h-screen pt-16 pb-20">
<div className="w-full max-w-6xl mx-auto px-4 md:px-6 lg:px-8">
<article className="w-full mx-auto bg-black/80 backdrop-filter backdrop-blur-sm rounded-2xl overflow-hidden border border-purple-500/20 shadow-xl shadow-purple-900/20">
<article className="w-full mx-auto bg-black/80 backdrop-filter backdrop-blur-sm rounded-2xl overflow-hidden border border-[#d900ff]/20 shadow-xl shadow-[#d900ff]/20">
<div className="grid md:grid-cols-5 gap-0">
{/* Left column: Title and info (3/5 width) */}
<div className="md:col-span-3 p-8 md:p-10">
......@@ -301,12 +305,12 @@ export default function Live({ data, slug, images }) {
{timeToEvent !== null && (
<div className="mb-8">
{timeToEvent >= 0 ? (
<div className="inline-flex items-center bg-black/60 p-4 rounded-lg border border-purple-500/30">
<div className="font-mono text-2xl font-bold mr-3 text-purple-400">{timeString}</div>
<div className="inline-flex items-center bg-black/60 p-4 rounded-lg border border-[#d900ff]/30">
<div className="font-mono text-2xl font-bold mr-3 text-[#d900ff]">{timeString}</div>
<div className="text-gray-300">avant l'événement</div>
</div>
) : (
<div className="inline-flex items-center bg-black/60 p-4 rounded-lg border border-purple-500/30">
<div className="inline-flex items-center bg-black/60 p-4 rounded-lg border border-[#d900ff]/30">
<div className="text-gray-300">Événement passé</div>
</div>
)}
......@@ -320,7 +324,7 @@ export default function Live({ data, slug, images }) {
href={data.frontmatter.ctaURL}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center justify-center px-5 py-3 border border-transparent text-base font-medium rounded-md text-white bg-purple-600 hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-purple-500"
className="inline-flex items-center justify-center px-5 py-3 border border-transparent text-base font-medium rounded-md text-white bg-[#8900b3] hover:bg-[#a700d1] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[#d900ff]"
>
{data.frontmatter.ctaText || 'S\'inscrire'}
</a>
......@@ -337,19 +341,19 @@ export default function Live({ data, slug, images }) {
</div>
{/* Right column: status and teasers (2/5 width) */}
<div className="md:col-span-2 bg-black/80 p-8 md:p-10 border-t md:border-t-0 md:border-l border-purple-500/20">
<div className="md:col-span-2 bg-black/80 p-8 md:p-10 border-t md:border-t-0 md:border-l border-[#d900ff]/20">
{/* Upcoming drops section */}
{upcomingDrops.length > 0 && (
<div className="mb-8 bg-black/50 border border-purple-500/30 rounded-lg p-4">
<h3 className="text-xl font-bold text-purple-400 mb-4">Prochains drops</h3>
<div className="mb-8 bg-black/50 border border-[#d900ff]/30 rounded-lg p-4">
<h3 className="text-xl font-bold text-[#d900ff] mb-4">Prochains drops</h3>
<div className="space-y-4">
{upcomingDrops.map((drop, index) => (
<div key={index} className="flex items-center justify-between gap-4 border-b border-purple-500/10 pb-4 last:border-0 last:pb-0">
<div key={index} className="flex items-center justify-between gap-4 border-b border-[#d900ff]/10 pb-4 last:border-0 last:pb-0">
<div>
<div className="text-lg font-medium text-gray-200">{drop.name}</div>
<div className="text-sm text-gray-400">{formatPreciseDateTime(drop.date)}</div>
</div>
<div className="font-mono text-lg text-purple-300">{getTimeDifferenceString(drop.date)}</div>
<div className="font-mono text-lg text-[#ff3d7b]">{getTimeDifferenceString(drop.date)}</div>
</div>
))}
</div>
......@@ -362,10 +366,10 @@ export default function Live({ data, slug, images }) {
{/* Teasings */}
{teasingsToShow.length > 0 && (
<div>
<h3 className="text-xl font-bold text-purple-400 mb-4">Teasings</h3>
<h3 className="text-xl font-bold text-[#d900ff] mb-4">Teasings</h3>
<div className="space-y-6">
{teasingsToShow.map((teasing, index) => (
<div key={index} className="bg-black/50 border border-purple-500/30 rounded-lg p-4">
<div key={index} className="bg-black/50 border border-[#d900ff]/30 rounded-lg p-4">
<div dangerouslySetInnerHTML={renderMarkdown(teasing)} className="prose prose-sm prose-invert max-w-none" />
</div>
))}
......@@ -385,7 +389,7 @@ export default function Live({ data, slug, images }) {
{/* Description */}
<div>
<h2 className="text-2xl font-bold text-purple-400 mb-6">À propos de cet événement</h2>
<h2 className="text-2xl font-bold text-[#d900ff] mb-6">À propos de cet événement</h2>
<div
className="prose prose-lg prose-invert"
dangerouslySetInnerHTML={renderMarkdown(data.content)}
......@@ -400,11 +404,12 @@ export default function Live({ data, slug, images }) {
<div>
{images && images.length > 0 && (
<div>
<h2 className="text-2xl font-bold text-purple-400 mb-6">Galerie</h2>
<h2 className="text-2xl font-bold text-[#d900ff] mb-6">Galerie</h2>
<ImageGallery
images={images}
slug={slug}
alt={data.frontmatter.title}
className="filter grayscale hover:grayscale-0"
/>
</div>
)}
......
/* Add the ParVagues color variables globally */
:root {
--neon-down: #8900b3;
--neon-low: #a700d1;
--neon-high: #d900ff;
--coral: #ff3d7b;
--biomod: #5bc091;
--cigarette: #ff8c00;
}
\ No newline at end of file
/* ParVagues specific styles */
/* New Color Palette */
/* Fixing CSS Modules compatibility - defining colors in a local class */
.colorRoot {
--neon-down: #8900b3;
--neon-low: #a700d1;
--neon-high: #d900ff;
--coral: #ff3d7b;
--biomod: #5bc091;
--cigarette: #ff8c00;
}
/* This class can be added to the main container to provide color variables to all children */
.colorContainer {
composes: colorRoot;
}
.heroSection {
min-height: 100vh;
position: relative;
......@@ -9,9 +26,14 @@
.heroTitle {
font-size: clamp(4rem, 9vw, 9rem);
font-weight: 800;
margin: 1.5rem 0; /* less on the left and right */
padding: 0.5rem;
text-wrap: balance;
margin-bottom: 1.5rem 0;
padding-top: 0.5em;
padding-bottom: 0.1em;
-webkit-background-clip: text;
background-clip: text;
line-height: 0.9;
letter-spacing: -0.05em;
text-shadow: 0 0 10px rgba(217, 0, 255, 0.5);
}
.bgImage {
......@@ -30,11 +52,11 @@
position: relative;
z-index: 10;
min-height: 100vh;
background: linear-gradient(135deg, rgba(9,9,11,0.95) 0%, rgba(88,28,135,0.9) 50%, rgba(9,9,11,0.95) 100%);
background: linear-gradient(135deg, rgba(9,9,11,0.95) 0%, rgba(137,0,179,0.9) 50%, rgba(9,9,11,0.95) 100%);
}
.heroContent {
padding: 2rem 1rem;
padding: 2rem 3rem;
max-width: 1400px;
margin: 0 auto;
width: 100%;
......@@ -53,19 +75,6 @@
}
}
.heroTitle {
font-size: clamp(4rem, 12vw, 9rem);
font-weight: 800;
margin-bottom: 1.5rem;
padding-top: 0.5em;
padding-bottom: 0.1em;
background: linear-gradient(45deg, #a855f7, #ec4899, #8b5cf6);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
line-height: 0.9;
letter-spacing: -0.05em;
}
.heroSubtitle {
font-size: clamp(1.125rem, 3vw, 1.5rem);
......@@ -73,6 +82,19 @@
max-width: 600px;
line-height: 1.5;
margin-bottom: 3rem;
position: relative;
}
.heroSubtitle::after {
content: "";
position: absolute;
bottom: -10px;
left: 0;
width: 60%;
height: 3px;
background: var(--coral);
border-radius: 3px;
box-shadow: 0 0 10px var(--coral);
}
.ctaButton {
......@@ -82,25 +104,26 @@
z-index: 50;
background: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(8px);
border: 1px solid rgba(168, 85, 247, 0.3);
border: 1px solid rgba(217, 0, 255, 0.3);
padding: 0.75rem 1.5rem;
border-radius: 0.5rem;
color: #a855f7;
color: var(--neon-high);
transition: all 0.3s ease;
text-decoration: none;
font-weight: 500;
}
.ctaButton:hover {
background: rgba(168, 85, 247, 0.1);
border-color: #a855f7;
color: #ec4899;
background: rgba(217, 0, 255, 0.1);
border-color: var(--neon-high);
color: var(--coral);
box-shadow: 0 0 15px rgba(217, 0, 255, 0.5);
}
.plungeButton {
display: inline-flex;
align-items: center;
background: linear-gradient(45deg, #a855f7, #ec4899);
background: linear-gradient(45deg, var(--neon-low), var(--coral));
color: white;
padding: 1rem 2rem;
border-radius: 0.5rem;
......@@ -108,11 +131,41 @@
text-decoration: none;
transition: all 0.3s ease;
gap: 0.5rem;
position: relative;
overflow: hidden;
}
.plungeButton::before {
content: '';
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
background: linear-gradient(45deg, var(--neon-down), var(--neon-high), var(--coral), var(--cigarette));
z-index: -1;
animation: rotate 3s linear infinite;
opacity: 0;
transition: opacity 0.3s ease;
border-radius: 0.6rem;
}
.plungeButton:hover::before {
opacity: 1;
}
@keyframes rotate {
0% {
background-position: 0% 0%;
}
100% {
background-position: 200% 200%;
}
}
.plungeButton:hover {
transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(168, 85, 247, 0.3);
box-shadow: 0 10px 20px rgba(217, 0, 255, 0.3);
}
.sectionContainer {
......@@ -140,22 +193,24 @@
margin-bottom: 1.5rem;
padding-left: 2rem;
position: relative;
transition: all 0.3s ease;
}
.bulletPoint::before {
content: "→";
position: absolute;
left: 0;
color: #a855f7;
color: var(--neon-high);
font-weight: bold;
}
.codeContainer {
background: rgba(0, 0, 0, 0.7);
border: 1px solid rgba(168, 85, 247, 0.2);
border: 1px solid rgba(217, 0, 255, 0.2);
border-radius: 0.5rem;
overflow: hidden;
position: relative;
box-shadow: 0 5px 15px rgba(137, 0, 179, 0.2);
}
.terminalContainer {
......@@ -166,7 +221,7 @@
}
.terminalHeader {
background: #363636;
background: #262626;
padding: 0.5rem 1rem;
display: flex;
align-items: center;
......@@ -186,15 +241,15 @@
}
.redCircle {
background: #ff5f56;
background: var(--coral);
}
.yellowCircle {
background: #ffbd2e;
background: var(--cigarette);
}
.greenCircle {
background: #27ca42;
background: var(--biomod);
}
.terminalTitle {
......@@ -232,7 +287,7 @@
.codeContainer::-webkit-scrollbar-thumb,
.terminalContainer pre::-webkit-scrollbar-thumb {
background: #a855f7;
background: var(--neon-high);
border-radius: 3px;
}
......@@ -245,16 +300,17 @@
.albumCard {
background: rgba(0, 0, 0, 0.4);
border: 1px solid rgba(168, 85, 247, 0.2);
border: 1px solid rgba(217, 0, 255, 0.2);
border-radius: 0.5rem;
padding: 1.5rem;
transition: all 0.3s ease;
}
.albumCard:hover {
background: rgba(168, 85, 247, 0.05);
border-color: #a855f7;
background: rgba(217, 0, 255, 0.05);
border-color: var(--neon-high);
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(217, 0, 255, 0.2);
}
.playerContainer {
......@@ -273,15 +329,16 @@
transition: all 0.3s ease;
font-size: 0.875rem;
border-radius: 0.25rem;
background: rgba(168, 85, 247, 0.1);
border: 1px solid rgba(168, 85, 247, 0.2);
background: rgba(217, 0, 255, 0.1);
border: 1px solid rgba(217, 0, 255, 0.2);
}
.playerButton:hover {
color: #a855f7;
background: rgba(168, 85, 247, 0.2);
border-color: #a855f7;
color: var(--neon-high);
background: rgba(217, 0, 255, 0.2);
border-color: var(--neon-high);
transform: translateY(-1px);
box-shadow: 0 0 10px rgba(217, 0, 255, 0.3);
}
.socialLinks {
......@@ -306,21 +363,21 @@
}
.socialLink:hover {
color: #a855f7;
border-color: #a855f7;
background: rgba(168, 85, 247, 0.05);
color: var(--neon-high);
border-color: var(--neon-high);
background: rgba(217, 0, 255, 0.05);
transform: translateY(-2px);
}
.bulletPoint.cursor-pointer:hover {
background: rgba(168, 85, 247, 0.05);
background: rgba(217, 0, 255, 0.05);
border-radius: 0.5rem;
}
.footer {
text-align: center;
padding: 2rem;
border-top: 1px solid rgba(168, 85, 247, 0.1);
border-top: 1px solid rgba(217, 0, 255, 0.1);
background: rgba(0, 0, 0, 0.5);
}
......@@ -328,7 +385,7 @@
position: absolute;
inset: 0;
opacity: 0.6;
filter: blur(4px);
filter: grayscale(100%) brightness(0.3) contrast(1.2);
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(3, 1fr);
......@@ -339,7 +396,7 @@
position: absolute;
inset: 0;
opacity: 0.6;
filter: blur(4px);
filter: grayscale(100%) brightness(0.3) contrast(1.2);
}
.posterImage {
......@@ -352,38 +409,98 @@
.posterGradient {
position: absolute;
inset: 0;
background: linear-gradient(to bottom, rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0.9));
background: radial-gradient(circle at center, rgba(217, 0, 255, 0.2), rgba(0, 0, 0, 0.9));
}
.highlightText {
position: relative;
display: inline-block;
}
.highlightText::after {
content: "";
position: absolute;
bottom: -2px;
left: 0;
width: 100%;
height: 2px;
background: var(--coral);
border-radius: 2px;
box-shadow: 0 0 8px var(--coral);
}
.glitchEffect {
animation: glitch 8s linear infinite;
position: relative;
display: inline-block;
animation: subtle-pulse 4s infinite alternate;
letter-spacing: -0.03em;
color: white;
text-shadow:
0 0 5px rgba(217, 0, 255, 0.7),
0 0 10px rgba(217, 0, 255, 0.5);
font-weight: 900;
}
@keyframes glitch {
@keyframes subtle-pulse {
0% {
filter: none;
}
2% {
filter: hue-rotate(90deg);
}
3% {
filter: none;
}
4% {
clip-path: polygon(0 0, 100% 0, 100% 35%, 0 35%);
transform: translateX(-2px);
}
5% {
transform: translateX(0);
clip-path: none;
text-shadow:
0 0 5px rgba(217, 0, 255, 0.7),
0 0 10px rgba(217, 0, 255, 0.5);
}
97% {
filter: none;
}
98% {
filter: invert(0.1);
}
99% {
filter: none;
100% {
text-shadow:
0 0 8px rgba(217, 0, 255, 0.9),
0 0 15px rgba(217, 0, 255, 0.7),
0 0 25px rgba(217, 0, 255, 0.5);
}
}
.glitchEffect::before,
.glitchEffect::after {
content: attr(data-text);
position: absolute;
top: 0;
left: 0;
width: 100%;
opacity: 0;
}
.glitchEffect::before {
left: 2px;
text-shadow: -2px 0 var(--coral);
clip-path: polygon(0 0, 100% 0, 100% 35%, 0 35%);
}
.glitchEffect::after {
left: -2px;
text-shadow: -2px 0 var(--neon-high);
clip-path: polygon(0 65%, 100% 65%, 100% 100%, 0 100%);
}
.neonGradient {
background: linear-gradient(90deg,
var(--neon-down),
var(--neon-low),
var(--neon-high),
var(--coral)
);
opacity: 0.15;
position: absolute;
inset: 0;
mix-blend-mode: screen;
pointer-events: none;
}
.logoContainer {
display: flex;
flex-direction: column;
align-items: center;
max-width: 300px;
margin-bottom: 2rem;
}
.logoImage {
width: 100%;
height: auto;
filter: drop-shadow(0 0 10px rgba(217, 0, 255, 0.5));
}
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