mirror of
https://github.com/LCE-Hub/lce-hub.github.io.git
synced 2026-08-20 04:27:36 +00:00
Music and sfx
This commit is contained in:
parent
3d6a32e227
commit
2140eb53c7
|
|
@ -26,6 +26,9 @@
|
||||||
<div class="menu-container">
|
<div class="menu-container">
|
||||||
<header class="menu-header">
|
<header class="menu-header">
|
||||||
<img src="/MenuTitle.png" alt="Emerald Legacy" class="menu-title">
|
<img src="/MenuTitle.png" alt="Emerald Legacy" class="menu-title">
|
||||||
|
<button id="audio-toggle" class="audio-btn" title="Toggle Music">
|
||||||
|
<i class="fas fa-volume-up"></i>
|
||||||
|
</button>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<nav class="menu-tabs">
|
<nav class="menu-tabs">
|
||||||
|
|
|
||||||
BIN
public/music/music1.ogg
Normal file
BIN
public/music/music1.ogg
Normal file
Binary file not shown.
BIN
public/music/music2.ogg
Normal file
BIN
public/music/music2.ogg
Normal file
Binary file not shown.
BIN
public/music/music3.ogg
Normal file
BIN
public/music/music3.ogg
Normal file
Binary file not shown.
BIN
public/music/music4.ogg
Normal file
BIN
public/music/music4.ogg
Normal file
Binary file not shown.
BIN
public/music/music5.ogg
Normal file
BIN
public/music/music5.ogg
Normal file
Binary file not shown.
BIN
public/sounds/back.ogg
Normal file
BIN
public/sounds/back.ogg
Normal file
Binary file not shown.
BIN
public/sounds/click.wav
Normal file
BIN
public/sounds/click.wav
Normal file
Binary file not shown.
BIN
public/sounds/levelup.ogg
Normal file
BIN
public/sounds/levelup.ogg
Normal file
Binary file not shown.
BIN
public/sounds/orb.ogg
Normal file
BIN
public/sounds/orb.ogg
Normal file
Binary file not shown.
BIN
public/sounds/pop.wav
Normal file
BIN
public/sounds/pop.wav
Normal file
Binary file not shown.
BIN
public/sounds/wood click.wav
Normal file
BIN
public/sounds/wood click.wav
Normal file
Binary file not shown.
109
src/main.ts
109
src/main.ts
|
|
@ -1,6 +1,80 @@
|
||||||
import './style.css';
|
import './style.css';
|
||||||
|
|
||||||
|
class AudioManager {
|
||||||
|
private musicFiles = ['/music/music1.ogg', '/music/music2.ogg', '/music/music3.ogg', '/music/music4.ogg', '/music/music5.ogg'];
|
||||||
|
private musicIndex = Math.floor(Math.random() * 5);
|
||||||
|
private music: HTMLAudioElement;
|
||||||
|
private isMuted = false;
|
||||||
|
private hasInteracted = false;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.music = new Audio(this.musicFiles[this.musicIndex]);
|
||||||
|
this.music.volume = 0.3;
|
||||||
|
this.music.preload = 'auto';
|
||||||
|
this.music.addEventListener('ended', () => this.nextTrack());
|
||||||
|
|
||||||
|
const savedMute = localStorage.getItem('emerald-muted') === 'true';
|
||||||
|
if (savedMute) {
|
||||||
|
this.isMuted = true;
|
||||||
|
this.music.pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private nextTrack() {
|
||||||
|
this.musicIndex = (this.musicIndex + 1) % this.musicFiles.length;
|
||||||
|
this.music.src = this.musicFiles[this.musicIndex];
|
||||||
|
this.music.preload = 'auto';
|
||||||
|
if (!this.isMuted) this.music.play().catch(() => { });
|
||||||
|
}
|
||||||
|
|
||||||
|
public start() {
|
||||||
|
if (this.hasInteracted || this.isMuted) return;
|
||||||
|
this.hasInteracted = true;
|
||||||
|
this.music.play().catch(() => { });
|
||||||
|
}
|
||||||
|
|
||||||
|
public toggleMute() {
|
||||||
|
this.isMuted = !this.isMuted;
|
||||||
|
localStorage.setItem('emerald-muted', String(this.isMuted));
|
||||||
|
if (this.isMuted) this.music.pause();
|
||||||
|
else {
|
||||||
|
if (this.hasInteracted) this.music.play().catch(() => { });
|
||||||
|
else {
|
||||||
|
this.hasInteracted = true;
|
||||||
|
this.music.play().catch(() => { });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateUI() {
|
||||||
|
const btn = document.getElementById('audio-toggle');
|
||||||
|
if (btn) {
|
||||||
|
btn.classList.toggle('muted', this.isMuted);
|
||||||
|
const icon = btn.querySelector('i');
|
||||||
|
if (icon) icon.className = this.isMuted ? 'fas fa-volume-mute' : 'fas fa-volume-up';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public playSFX(file: string) {
|
||||||
|
const sfx = new Audio(`/sounds/${file}`);
|
||||||
|
sfx.volume = 0.4;
|
||||||
|
sfx.play().catch(() => { });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const audio = new AudioManager();
|
||||||
|
audio.updateUI();
|
||||||
|
|
||||||
|
const startAudio = () => audio.start();
|
||||||
|
document.addEventListener('click', startAudio, { once: true });
|
||||||
|
document.getElementById('audio-toggle')?.addEventListener('click', () => {
|
||||||
|
audio.playSFX('click.wav');
|
||||||
|
audio.toggleMute();
|
||||||
|
});
|
||||||
|
|
||||||
const tabs = document.querySelectorAll('.tab-item');
|
const tabs = document.querySelectorAll('.tab-item');
|
||||||
const contents = document.querySelectorAll('.tab-content');
|
const contents = document.querySelectorAll('.tab-content');
|
||||||
|
|
||||||
|
|
@ -10,6 +84,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
if (index < 0) index = tabs.length - 1;
|
if (index < 0) index = tabs.length - 1;
|
||||||
if (index >= tabs.length) index = 0;
|
if (index >= tabs.length) index = 0;
|
||||||
|
|
||||||
|
if (activeIndex !== index) audio.playSFX('click.wav');
|
||||||
activeIndex = index;
|
activeIndex = index;
|
||||||
|
|
||||||
tabs.forEach((tab, i) => {
|
tabs.forEach((tab, i) => {
|
||||||
|
|
@ -44,7 +119,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
];
|
];
|
||||||
let screenIndex = 0;
|
let screenIndex = 0;
|
||||||
|
|
||||||
const rotateScreenshot = (dir: number) => {
|
const rotateScreenshot = (dir: number, isManual = false) => {
|
||||||
|
if (isManual) audio.playSFX('wood click.wav');
|
||||||
screenIndex = (screenIndex + dir + screenshots.length) % screenshots.length;
|
screenIndex = (screenIndex + dir + screenshots.length) % screenshots.length;
|
||||||
if (carouselImg) {
|
if (carouselImg) {
|
||||||
carouselImg.style.opacity = '0';
|
carouselImg.style.opacity = '0';
|
||||||
|
|
@ -55,8 +131,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
document.querySelector('.carousel-arrow.left')?.addEventListener('click', () => rotateScreenshot(-1));
|
document.querySelector('.carousel-arrow.left')?.addEventListener('click', () => rotateScreenshot(-1, true));
|
||||||
document.querySelector('.carousel-arrow.right')?.addEventListener('click', () => rotateScreenshot(1));
|
document.querySelector('.carousel-arrow.right')?.addEventListener('click', () => rotateScreenshot(1, true));
|
||||||
|
|
||||||
const repo = 'Emerald-Legacy-Launcher/Emerald-Legacy-Launcher';
|
const repo = 'Emerald-Legacy-Launcher/Emerald-Legacy-Launcher';
|
||||||
const modal = document.getElementById('download-modal');
|
const modal = document.getElementById('download-modal');
|
||||||
|
|
@ -102,7 +178,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
const specific = assets.find(a => a.name.endsWith('.AppImage') && a.name.includes(archTag));
|
const specific = assets.find(a => a.name.endsWith('.AppImage') && a.name.includes(archTag));
|
||||||
if (specific) return specific;
|
if (specific) return specific;
|
||||||
|
|
||||||
// Fallback to any AppImage
|
|
||||||
return assets.find(a => a.name.endsWith('.AppImage'));
|
return assets.find(a => a.name.endsWith('.AppImage'));
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -111,6 +186,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
const openDownloadModal = (osType: string) => {
|
const openDownloadModal = (osType: string) => {
|
||||||
if (!modal || !modalOptions || !modalTitle) return;
|
if (!modal || !modalOptions || !modalTitle) return;
|
||||||
|
|
||||||
|
audio.playSFX('click.wav');
|
||||||
const { arch } = detectOS();
|
const { arch } = detectOS();
|
||||||
let filteredAssets = [];
|
let filteredAssets = [];
|
||||||
let title = 'Select Downloader';
|
let title = 'Select Downloader';
|
||||||
|
|
@ -133,7 +209,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
const isRecommended = asset.name === recommended?.name;
|
const isRecommended = asset.name === recommended?.name;
|
||||||
return `
|
return `
|
||||||
<div class="modal-btn-container">
|
<div class="modal-btn-container">
|
||||||
<a href="${asset.browser_download_url}" class="main-btn">
|
<a href="${asset.browser_download_url}" class="main-btn" onclick="window.playAudioSFX('levelup.ogg')">
|
||||||
<span>${asset.name.split('_').pop()?.split('-').pop() || asset.name}</span>
|
<span>${asset.name.split('_').pop()?.split('-').pop() || asset.name}</span>
|
||||||
</a>
|
</a>
|
||||||
${isRecommended ? '<span class="splash-text">Recommended!</span>' : ''}
|
${isRecommended ? '<span class="splash-text">Recommended!</span>' : ''}
|
||||||
|
|
@ -144,6 +220,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
modal.classList.add('active');
|
modal.classList.add('active');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
(window as any).playAudioSFX = (file: string) => audio.playSFX(file);
|
||||||
|
|
||||||
const updateDownloadButtons = async () => {
|
const updateDownloadButtons = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`https://api.github.com/repos/${repo}/releases/latest`);
|
const response = await fetch(`https://api.github.com/repos/${repo}/releases/latest`);
|
||||||
|
|
@ -174,11 +252,24 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
closeModal?.addEventListener('click', () => modal?.classList.remove('active'));
|
closeModal?.addEventListener('click', () => {
|
||||||
modal?.addEventListener('click', (e) => { if (e.target === modal) modal.classList.remove('active'); });
|
audio.playSFX('back.ogg');
|
||||||
window.addEventListener('keydown', (e) => { if (e.key === 'Escape') modal?.classList.remove('active'); });
|
modal?.classList.remove('active');
|
||||||
|
});
|
||||||
|
modal?.addEventListener('click', (e) => {
|
||||||
|
if (e.target === modal) {
|
||||||
|
audio.playSFX('back.ogg');
|
||||||
|
modal.classList.remove('active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
window.addEventListener('keydown', (e) => {
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
if (modal?.classList.contains('active')) audio.playSFX('back.ogg');
|
||||||
|
modal?.classList.remove('active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
updateDownloadButtons();
|
updateDownloadButtons();
|
||||||
|
|
||||||
setInterval(() => rotateScreenshot(1), 5000);
|
setInterval(() => rotateScreenshot(1, false), 5000);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -89,8 +89,46 @@ body {
|
||||||
|
|
||||||
.menu-header {
|
.menu-header {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.audio-btn {
|
||||||
|
position: absolute;
|
||||||
|
right: 40px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
background: #000;
|
||||||
|
border: 4px solid #7c7c7c;
|
||||||
|
border-right-color: #262626;
|
||||||
|
border-bottom-color: #262626;
|
||||||
|
color: #fff;
|
||||||
|
padding: 8px 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: transform 0.1s;
|
||||||
|
z-index: 100;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.audio-btn:hover {
|
||||||
|
transform: translateY(-50%) scale(1.1);
|
||||||
|
outline: 4px solid var(--highlight-yellow);
|
||||||
|
}
|
||||||
|
|
||||||
|
.audio-btn i {
|
||||||
|
transition: color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.audio-btn.muted i {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.menu-title {
|
.menu-title {
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
width: 90%;
|
width: 90%;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue