6 Commits

3 changed files with 239 additions and 13 deletions

View File

@@ -4,9 +4,6 @@ import { Inter } from "next/font/google";
import "./globals.css";
import { ServiceWrapper } from "@/components/ServiceWrapper";
import Tag from "@/tag/Tag";
import { BackgroundLofiMusicPlayer } from "@/components/BackgroundLofiMusicPlayer";
// Create the BackgroundLofiMusicPlayer component file at src/components/BackgroundLofiMusicPlayer.tsx
const notoSans = Noto_Sans({
variable: "--font-noto-sans", subsets: ["latin"],
@@ -31,7 +28,6 @@ export default function RootLayout({
<body
className={`${notoSans.variable} ${inter.variable} antialiased`}
>
<BackgroundLofiMusicPlayer />
<Tag />
{children}

View File

@@ -10,6 +10,7 @@ import TestimonialCardOne from '@/components/sections/testimonial/TestimonialCar
import ContactFaq from '@/components/sections/contact/ContactFaq';
import FooterMedia from '@/components/sections/footer/FooterMedia';
import { Award, Sparkles, Users, Music } from "lucide-react";
import BackgroundMusicPlayer from '@/components/BackgroundMusicPlayer';
export default function LandingPage() {
return (
@@ -25,6 +26,7 @@ export default function LandingPage() {
secondaryButtonStyle="glass"
headingFontWeight="normal"
>
<BackgroundMusicPlayer />
<div id="nav" data-section="nav">
<NavbarStyleCentered
navItems={[
@@ -42,8 +44,95 @@ export default function LandingPage() {
/>
</div>
<style>{`
@keyframes scaleHover {
from { transform: scale(1); }
to { transform: scale(1.02); }
}
@keyframes shadowDepth {
from { box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); }
to { box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3); }
}
@keyframes slideInLeft {
from { transform: translateX(-20px); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
@keyframes fadeGlow {
from { filter: drop-shadow(0 0 0px rgba(168, 85, 247, 0)); }
to { filter: drop-shadow(0 0 20px rgba(168, 85, 247, 0.6)); }
}
@keyframes slideInRight {
from { transform: translateX(20px); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
@keyframes glowPulse {
from { box-shadow: 0 0 10px rgba(59, 130, 246, 0.5); }
to { box-shadow: 0 0 30px rgba(59, 130, 246, 0.8); }
}
@keyframes floatUp {
from { transform: translateY(10px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
#hero-section {
transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}
#hero-section:hover {
animation: scaleHover 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
filter: drop-shadow(0 25px 50px rgba(0, 0, 0, 0.25));
}
#about-section {
transition: all 0.6s ease-out;
}
#about-section:hover {
animation: shadowDepth 0.6s ease-out forwards;
transform: translateY(-5px);
}
#features-section {
transition: all 0.5s ease-in-out;
}
#features-section:hover {
animation: slideInLeft 0.5s ease-in-out forwards;
filter: brightness(1.05);
}
#team-section {
transition: all 0.7s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
#team-section:hover {
animation: fadeGlow 0.7s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards;
transform: scale(1.01);
}
#testimonials-section {
transition: all 0.6s ease-out;
}
#testimonials-section:hover {
animation: slideInRight 0.6s ease-out forwards;
box-shadow: 0 15px 35px rgba(168, 85, 247, 0.2);
}
#contact-section {
transition: all 0.5s ease-in-out;
}
#contact-section:hover {
animation: glowPulse 0.5s ease-in-out forwards;
transform: translateY(-3px);
}
footer {
transition: all 0.6s ease-out;
}
footer:hover {
animation: floatUp 0.6s ease-out forwards;
box-shadow: 0 -10px 30px rgba(59, 130, 246, 0.3);
}
`}</style>
<div id="hero-section" data-section="hero-section">
<HeroLogoBillboardSplit
<HeroImageOverlay
logoText="Harmony Studios"
description="Where musical excellence meets cutting-edge technology. We craft sonic experiences that resonate with artists and audiences alike."
background={{ variant: "radial-gradient" }}
@@ -52,17 +141,16 @@ export default function LandingPage() {
{ text: "Book a Session", href: "#contact-section" }
]}
buttonAnimation="slide-up"
layoutOrder="default"
imageSrc="https://img.b2bpic.net/free-photo/piano-key-guitar-string-musician-creativity-generated-by-ai_188544-25821.jpg"
imageAlt="Elegant recording studio setup with professional audio equipment"
mediaAnimation="blur-reveal"
frameStyle="card"
overlayOpacity={0.4}
ariaLabel="Hero section featuring Harmony Studios branding and studio imagery"
/>
</div>
<div id="about-section" data-section="about-section">
<MetricSplitMediaAbout
<TimelineAbout
title="Crafting Soundscapes That Define Artistry"
description="With over two decades of experience, our studio has been the creative sanctuary where legendary tracks are born. We blend technical excellence with artistic vision to deliver recordings that resonate beyond the studio walls."
metrics={[
@@ -83,7 +171,7 @@ export default function LandingPage() {
</div>
<div id="features-section" data-section="features-section">
<FeatureCardThree
<FeatureCardTwo
title="Professional Recording Services"
description="State-of-the-art facilities and expert engineers to bring your musical vision to life with unparalleled sound quality."
tag="Studio Excellence"
@@ -116,7 +204,7 @@ export default function LandingPage() {
</div>
<div id="team-section" data-section="team-section">
<TeamCardSix
<TeamCardFour
members={[
{
id: "member-1", name: "Alexandra Chen", role: "Lead Producer & Engineer", imageSrc: "https://img.b2bpic.net/free-photo/music-producer-using-his-headphones-mix-master-session_482257-121292.jpg", imageAlt: "Alexandra Chen, Lead Producer & Engineer at Melody Studio"
@@ -155,7 +243,7 @@ export default function LandingPage() {
</div>
<div id="testimonials-section" data-section="testimonials-section">
<TestimonialCardOne
<TestimonialCardThree
testimonials={[
{
id: "testimonial-1", name: "Alexandra Chen", role: "Lead Vocalist", company: "Midnight Echoes", rating: 5,
@@ -190,7 +278,7 @@ export default function LandingPage() {
</div>
<div id="contact-section" data-section="contact-section">
<ContactFaq
<ContactForm
faqs={[
{
id: "faq-1", title: "What recording packages do you offer?", content: "We provide comprehensive recording packages tailored to different needs, from basic tracking sessions to full production services including mixing, mastering, and artist development."
@@ -220,7 +308,7 @@ export default function LandingPage() {
</div>
<div id="footer-section" data-section="footer-section">
<FooterMedia
<FooterMinimal
imageSrc="https://img.b2bpic.net/free-photo/artist-props-photography_23-2148885625.jpg"
imageAlt="Elegant music studio interior with vintage instruments and warm lighting"
columns={[

View File

@@ -0,0 +1,142 @@
'use client';
import { useState, useEffect, useRef } from 'react';
import { Volume2, VolumeX, Play, Pause } from 'lucide-react';
interface Props {}
export default function BackgroundMusicPlayer({}: Props) {
const audioRef = useRef<HTMLAudioElement>(null);
const [isPlaying, setIsPlaying] = useState(false);
const [volume, setVolume] = useState(0.5);
const [isLoaded, setIsLoaded] = useState(false);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const audio = audioRef.current;
if (!audio) return;
audio.volume = volume;
}, [volume]);
useEffect(() => {
const audio = audioRef.current;
if (!audio) return;
const handleCanPlay = () => {
setIsLoaded(true);
setError(null);
};
const handleError = () => {
setError('Failed to load audio');
setIsPlaying(false);
};
const handleEnded = () => {
audio.currentTime = 0;
audio.play().catch(() => {
setIsPlaying(false);
});
};
audio.addEventListener('canplay', handleCanPlay);
audio.addEventListener('error', handleError);
audio.addEventListener('ended', handleEnded);
return () => {
audio.removeEventListener('canplay', handleCanPlay);
audio.removeEventListener('error', handleError);
audio.removeEventListener('ended', handleEnded);
};
}, []);
const togglePlayPause = async () => {
const audio = audioRef.current;
if (!audio) return;
try {
if (isPlaying) {
audio.pause();
setIsPlaying(false);
} else {
await audio.play();
setIsPlaying(true);
}
} catch (err) {
setError('Autoplay policy prevented playback');
setIsPlaying(false);
}
};
const handleVolumeChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const newVolume = parseFloat(e.target.value);
setVolume(newVolume);
};
return (
<div className="fixed bottom-6 right-6 bg-gradient-to-br from-slate-900 to-slate-800 rounded-lg shadow-2xl p-4 w-80 border border-slate-700">
<audio
ref={audioRef}
src="https://www.freepik.com/audio/tune/static"
loop
crossOrigin="anonymous"
/>
<div className="space-y-4">
<div className="flex items-center justify-between">
<h3 className="text-sm font-semibold text-white">Background Music</h3>
<div className="text-xs text-slate-400">
{isLoaded ? 'Ready' : 'Loading...'}
</div>
</div>
{error && (
<div className="text-xs text-red-400 bg-red-950 bg-opacity-50 rounded px-2 py-1">
{error}
</div>
)}
<div className="flex items-center gap-3">
<button
onClick={togglePlayPause}
disabled={!isLoaded}
className="flex-shrink-0 bg-blue-600 hover:bg-blue-700 disabled:bg-slate-600 disabled:cursor-not-allowed text-white rounded-full p-2 transition-colors duration-200"
aria-label={isPlaying ? 'Pause' : 'Play'}
>
{isPlaying ? (
<Pause size={20} fill="currentColor" />
) : (
<Play size={20} fill="currentColor" />
)}
</button>
<div className="flex-1 flex items-center gap-2">
{volume === 0 ? (
<VolumeX size={18} className="text-slate-400 flex-shrink-0" />
) : (
<Volume2 size={18} className="text-slate-400 flex-shrink-0" />
)}
<input
type="range"
min="0"
max="1"
step="0.05"
value={volume}
onChange={handleVolumeChange}
className="w-full h-2 bg-slate-700 rounded-lg appearance-none cursor-pointer accent-blue-600"
aria-label="Volume"
/>
<span className="text-xs text-slate-400 w-8 text-right">
{Math.round(volume * 100)}%
</span>
</div>
</div>
<div className="text-xs text-slate-500 text-center">
{isPlaying ? 'Now playing' : 'Paused'}
</div>
</div>
</div>
);
}