File size: 6,034 Bytes
d790e98 abc2a72 d790e98 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
import React from 'react';
import { BrowserRouter as Router, Routes, Route, Navigate, Link } from 'react-router-dom';
import Hero from './components/Hero';
import SingleAnalysis from './components/SingleAnalysis';
import BatchAnalysis from './components/BatchAnalysis';
const App: React.FC = () => {
const [isPlaying, setIsPlaying] = React.useState(false);
const audioRef = React.useRef<HTMLAudioElement>(null);
React.useEffect(() => {
const audio = audioRef.current;
if (!audio) return;
audio.volume = 0.5;
// 1. Try to autoplay immediately
const playPromise = audio.play();
if (playPromise !== undefined) {
playPromise
.then(() => setIsPlaying(true))
.catch((error) => {
console.log("Autoplay blocked. Waiting for user interaction.", error);
setIsPlaying(false);
});
}
// 2. Add a global click listener as a fallback
// As soon as the user clicks ANYWHERE, we start the audio
const handleUserInteraction = () => {
if (audio.paused) {
audio.play()
.then(() => {
setIsPlaying(true);
// Remove listener once successful
document.removeEventListener('click', handleUserInteraction);
})
.catch(e => console.error("Play failed even after interaction:", e));
}
};
document.addEventListener('click', handleUserInteraction);
return () => {
document.removeEventListener('click', handleUserInteraction);
};
}, []);
const toggleAudio = () => {
if (audioRef.current) {
if (isPlaying) {
audioRef.current.pause();
} else {
audioRef.current.play();
}
setIsPlaying(!isPlaying);
}
};
return (
<Router>
<div className="text-white selection:bg-cyan-500/30 selection:text-cyan-200">
{/* Global Nav / Logo - Fixed and High Z-Index */}
<div className="fixed top-0 left-0 w-full p-6 z-50 pointer-events-none flex justify-between items-start">
<Link to="/" className="inline-flex items-center gap-3 px-4 py-2 rounded-full bg-slate-900/80 backdrop-blur-md border border-white/10 shadow-lg pointer-events-auto hover:border-cyan-500/50 transition-all cursor-pointer group">
{/* Logo Icon */}
<div className="w-8 h-8 rounded-full flex items-center justify-center overflow-hidden bg-white/5">
<img src="/static/logo.png" alt="Logo" className="w-full h-full object-cover" />
</div>
<span className="font-bold tracking-widest text-lg text-white group-hover:text-cyan-400 transition-colors">Samsung Prism Prototype</span>
</Link>
{/* Audio Toggle */}
<div className="relative">
{!isPlaying && (
<div className="absolute right-14 top-1/2 -translate-y-1/2 z-50 flex items-center">
{/* Gradient Border Container */}
<div className="relative p-[2px] rounded-full bg-gradient-to-r from-cyan-400 via-purple-500 to-pink-500 animate-pulse shadow-[0_0_15px_rgba(34,211,238,0.5)]">
{/* Inner Glass Content */}
<div className="bg-slate-950/90 backdrop-blur-sm rounded-full px-5 py-2.5 flex items-center gap-2">
<span className="text-xs font-bold !text-white whitespace-nowrap" style={{ color: '#ffffff', mixBlendMode: 'normal' }}>
✨ Don't miss the magic! 🎧
</span>
</div>
{/* Arrow pointing to button */}
<div className="absolute top-1/2 -right-1.5 -translate-y-1/2 w-3 h-3 bg-gradient-to-r from-purple-500 to-pink-500 rotate-45 transform origin-center -z-10" />
</div>
</div>
)}
<button
onClick={toggleAudio}
className={`pointer-events-auto w-10 h-10 rounded-full bg-slate-900/80 backdrop-blur-md border border-white/10 flex items-center justify-center hover:bg-white/10 transition-all group ${!isPlaying ? 'animate-pulse ring-2 ring-cyan-500/50' : ''}`}
title={isPlaying ? "Mute Background Music" : "Play Background Music"}
>
{isPlaying ? (
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-5 h-5 text-cyan-400 group-hover:scale-110 transition-transform">
<path strokeLinecap="round" strokeLinejoin="round" d="M19.114 5.636a9 9 0 010 12.728M16.463 8.288a5.25 5.25 0 010 7.424M6.75 8.25l4.72-4.72a.75.75 0 011.28.53v15.88a.75.75 0 01-1.28.53l-4.72-4.72H4.51c-.88 0-1.704-.507-1.938-1.354A9.01 9.01 0 012.25 12c0-.83.426-1.643 1.087-2.146.24-.184.459-.387.653-.611H6.75z" />
</svg>
) : (
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-5 h-5 text-slate-400 group-hover:text-white transition-colors">
<path strokeLinecap="round" strokeLinejoin="round" d="M17.25 9.75L19.5 12m0 0l2.25 2.25M19.5 12l2.25-2.25M19.5 12l-2.25 2.25m-10.5-6l4.72-4.72a.75.75 0 011.28.53v15.88a.75.75 0 01-1.28.53l-4.72-4.72H4.51c-.88 0-1.704-.507-1.938-1.354A9.01 9.01 0 012.25 12c0-.83.426-1.643 1.087-2.146.24-.184.459-.387.653-.611H6.75z" />
</svg>
)}
</button>
</div>
</div>
<audio
ref={audioRef}
src="/static/background.mp3"
loop
onError={(e) => console.error("Audio failed to load:", e)}
/>
<main className="animate-fade-in">
<Routes>
<Route path="/" element={<Hero />} />
<Route path="/single" element={<SingleAnalysis />} />
<Route path="/batch" element={<BatchAnalysis />} />
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
</main>
</div>
</Router>
);
};
export default App; |