Skip to content

Commit 939b2ab

Browse files
authored
Merge pull request #26 from abdegenius/feature/background-music-player
Feature/background music player
2 parents 736d9ba + 58f0e80 commit 939b2ab

10 files changed

Lines changed: 1802 additions & 1056 deletions

File tree

app/components/AudioProvider.tsx

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
"use client";
2+
import React, {
3+
createContext,
4+
useContext,
5+
useEffect,
6+
useState,
7+
useRef,
8+
} from "react";
9+
10+
11+
interface AudioContextType {
12+
musicVolume: number;
13+
setMusicVolume: (value: number) => void;
14+
sfxVolume: number;
15+
setSfxVolume: (value: number) => void;
16+
playBackgroundAudio: () => void;
17+
pauseBackgroundAudio: () => void;
18+
playAudioEffect: (src: string) => void;
19+
playingBackgroundAudio: boolean;
20+
}
21+
22+
const AudioContext = createContext<AudioContextType | undefined>(undefined);
23+
24+
export const useAudioCustom = () => {
25+
const context = useContext(AudioContext);
26+
if (!context) {
27+
throw new Error("useAudio must be used within a AudioProvider");
28+
}
29+
return context;
30+
};
31+
32+
export const AudioProvider: React.FC<{ children: React.ReactNode }> = ({
33+
children,
34+
}) => {
35+
const [musicVolume, setMusicVolume] = useState(0.3); // music volume 30%
36+
const [sfxVolume, setSfxVolume] = useState(1.0); // audio effect volume 100%
37+
const backgroundAudioRef = useRef<HTMLAudioElement | null>(null);
38+
39+
const [playingBackgroundAudio, setplayingBackgroundAudio] = useState(false);
40+
41+
useEffect(() => {
42+
backgroundAudioRef.current = new Audio("./assets/music/bg.mp3");
43+
backgroundAudioRef.current.loop = true;
44+
backgroundAudioRef.current.volume = musicVolume;
45+
}, []);
46+
47+
useEffect(() => {
48+
if (backgroundAudioRef.current) {
49+
backgroundAudioRef.current.volume = musicVolume;
50+
}
51+
}, [musicVolume]);
52+
53+
const playBackgroundAudio = () => {
54+
setplayingBackgroundAudio(true);
55+
backgroundAudioRef.current
56+
?.play()
57+
.catch((error) =>
58+
console.error("Error playing background music:", error)
59+
);
60+
};
61+
62+
const pauseBackgroundAudio = () => {
63+
setplayingBackgroundAudio(false);
64+
backgroundAudioRef.current?.pause();
65+
};
66+
67+
const playAudioEffect = (src: string) => {
68+
const audioEffect = new Audio(src);
69+
audioEffect.volume = sfxVolume;
70+
audioEffect.play();
71+
};
72+
73+
return (
74+
<AudioContext.Provider
75+
value={{
76+
musicVolume,
77+
setMusicVolume,
78+
sfxVolume,
79+
setSfxVolume,
80+
playBackgroundAudio,
81+
pauseBackgroundAudio,
82+
playAudioEffect,
83+
playingBackgroundAudio,
84+
}}
85+
>
86+
{children}
87+
</AudioContext.Provider>
88+
);
89+
};

app/components/Header.tsx

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
"use client";
2+
import { useAudioCustom } from "./AudioProvider";
3+
import UNMUTE from "@/public/assets/images/unmute.png";
4+
import MUTED from "@/public/assets/images/muted.png";
5+
import Image from "next/image";
6+
import { WalletConnectorModal } from "./WalletConnector";
7+
8+
export default function Header() {
9+
const { playBackgroundAudio, pauseBackgroundAudio, playingBackgroundAudio } =
10+
useAudioCustom();
11+
return (
12+
<>
13+
<div className="absolute top-4 right-4 sm:top-8 sm:right-8 flex items-center gap-4">
14+
<div className="h-[40px] sm:h-[62px] w-[50px] sm:w-[72px] bg-[#222C38] transform -skew-x-12 flex justify-center items-center">
15+
{!playingBackgroundAudio && (
16+
<button
17+
type="button"
18+
onClick={() => {
19+
playBackgroundAudio();
20+
}}
21+
className="cursor-pointer"
22+
>
23+
<Image src={MUTED} alt="paused" width={48} height={48} />
24+
</button>
25+
)}
26+
{playingBackgroundAudio && (
27+
<button
28+
type="button"
29+
onClick={() => {
30+
pauseBackgroundAudio();
31+
}}
32+
className="cursor-pointer"
33+
>
34+
<Image src={UNMUTE} alt="playing" width={48} height={48} />
35+
</button>
36+
)}
37+
</div>
38+
<WalletConnectorModal />
39+
</div>
40+
</>
41+
);
42+
}

app/layout.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { Metadata } from "next";
2+
import { AudioProvider } from "./components/AudioProvider";
23
import { Geist, Geist_Mono } from "next/font/google";
34
import "./globals.css";
45
import StarknetProvider from "./components/starknet-provider";
@@ -18,6 +19,8 @@ export const metadata: Metadata = {
1819
description: "Generated by create next app",
1920
};
2021

22+
// const { isPlaying, volume, togglePlay, setVolume } = useAudio()
23+
2124
export default function RootLayout({
2225
children,
2326
}: Readonly<{
@@ -28,7 +31,9 @@ export default function RootLayout({
2831
<body
2932
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
3033
>
31-
<StarknetProvider>{children}</StarknetProvider>
34+
<StarknetProvider>
35+
<AudioProvider>{children}</AudioProvider>
36+
</StarknetProvider>
3237
</body>
3338
</html>
3439
);

app/page.tsx

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
1-
"use client";
2-
31
import Image from "next/image";
42
import Link from "next/link";
5-
import { WalletConnectorModal } from "./components/WalletConnector";
3+
import Header from "./components/Header";
4+
5+
// import WalletConnectButton from './components/WalletConnectButton';
66

77
export default function Home() {
88
return (
99
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)] bg-[url('/background.svg')] bg-no-repeat bg-cover">
10-
<div className="absolute top-4 right-4 sm:top-8 sm:right-8 flex items-center gap-4">
11-
<div className="h-[40px] sm:h-[62px] w-[50px] sm:w-[72px] bg-[#222C38] transform -skew-x-12"></div>
12-
<WalletConnectorModal />
13-
</div>
14-
10+
<Header />
1511
<main className="flex flex-col gap-4 row-start-2 items-center w-full mt-12 sm:mt-20">
1612
<div className="flex flex-col gap-4 w-full items-center sm:items-start sm:ml-8">
1713
<Image

app/profile/page.tsx

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Bowlby_One_SC } from "next/font/google";
2-
2+
import Header from "../components/Header";
33
const bowlby = Bowlby_One_SC({
44
weight: "400",
55
subsets: ["latin"],
@@ -11,14 +11,7 @@ export default function Profile() {
1111
<div
1212
className={`${bowlby.variable} flex flex-col items-center justify-center min-h-screen p-8 pb-20 sm:p-20 bg-[url('/background.svg')] bg-no-repeat bg-cover`}
1313
>
14-
<div className="absolute top-4 right-4 sm:top-8 sm:right-8 flex items-center gap-4">
15-
<button className="relative bg-[#222C38] transform -skew-x-12 px-4 sm:px-8 h-[40px] sm:h-[62px]">
16-
<span className="text-[#F3F5FF] text-sm sm:text-base font-bold transform skew-x-12">
17-
CONNECT WALLET
18-
</span>
19-
</button>
20-
</div>
21-
14+
<Header />
2215
<main className="w-full max-w-4xl flex flex-col mx-auto">
2316
<h1 className="text-[32px] font-bold self-start ml-6">PROFILE</h1>
2417

0 commit comments

Comments
 (0)