replace icons, improve music

This commit is contained in:
Aidan 2025-01-08 09:33:27 -05:00
parent b88c258896
commit 2011d7a83e
7 changed files with 128 additions and 67 deletions

View File

@ -3,13 +3,20 @@ import Link from 'next/link';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faArrowLeft } from '@fortawesome/free-solid-svg-icons'; import { faArrowLeft } from '@fortawesome/free-solid-svg-icons';
const BackButton: React.FC<{ href: string }> = ({ href }) => { interface BackButtonProps {
href: string;
label?: string;
}
const BackButton: React.FC<BackButtonProps> = ({ href, label = 'Back' }) => {
return ( return (
<Link href={href} legacyBehavior> <Link
<a className="bg-gray-800 hover:bg-gray-700 text-white font-bold py-2 px-4 mt-4 rounded inline-flex items-center"> href={href}
<FontAwesomeIcon icon={faArrowLeft} className="mr-2" /> className="inline-flex items-center px-4 py-2 mt-4 text-white bg-gray-800 rounded shadow-md transition-all duration-300 ease-in-out hover:bg-gray-700 hover:shadow-lg hover:-translate-y-0.5 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500"
Back aria-label={`Go back to ${label}`}
</a> >
<FontAwesomeIcon icon={faArrowLeft} className="mr-2" />
{label}
</Link> </Link>
); );
}; };

View File

@ -0,0 +1,12 @@
import { Loader2 } from 'lucide-react';
const LoadingSpinner: React.FC = () => {
return (
<div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50">
<Loader2 className="w-12 h-12 text-white animate-spin" />
</div>
);
};
export default LoadingSpinner;

View File

@ -2,48 +2,45 @@
import { useState, useEffect } from 'react'; import { useState, useEffect } from 'react';
import Image from 'next/image'; import Image from 'next/image';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Play, SkipBack, SkipForward, ChevronLeft, ChevronRight } from 'lucide-react';
import { faPlay, faStepBackward, faStepForward, faArrowLeft, faArrowRight } from '@fortawesome/free-solid-svg-icons'; import LoadingSpinner from './LoadingSpinner';
interface Song {
albumArt: string;
name: string;
artist: string;
duration: string;
link?: string;
}
interface Period {
timePeriod: string;
songs: Song[];
}
export default function Home() { export default function Home() {
const [timePeriod, setTimePeriod] = useState('2020s'); const [timePeriod, setTimePeriod] = useState('Summer 2024');
interface Song {
albumArt: string;
name: string;
artist: string;
duration: string;
link?: string;
}
const [songs, setSongs] = useState<Song[]>([]); const [songs, setSongs] = useState<Song[]>([]);
const [currentIndex, setCurrentIndex] = useState(0); const [currentIndex, setCurrentIndex] = useState(0);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => { useEffect(() => {
setIsLoading(true);
fetch('/data/music.json') fetch('/data/music.json')
.then(response => response.json()) .then(response => response.json())
.then(data => { .then((data: Period[]) => {
interface Song { const selectedPeriod = data.find((period) => period.timePeriod === timePeriod);
albumArt: string; const songsList = selectedPeriod ? selectedPeriod.songs : [];
name: string;
artist: string;
duration: string;
}
interface Period {
timePeriod: string;
songs: Song[];
}
const selectedPeriod = data.find((period: Period) => period.timePeriod === timePeriod); const songsList = selectedPeriod ? selectedPeriod.songs : [];
setSongs(songsList); setSongs(songsList);
setCurrentIndex(Math.floor(Math.random() * songsList.length)); setCurrentIndex(Math.floor(Math.random() * songsList.length));
setIsLoading(false);
})
.catch(error => {
console.error('Error fetching music data:', error);
setIsLoading(false);
}); });
}, [timePeriod]); }, [timePeriod]);
useEffect(() => {
const selectElement = document.getElementById('timePeriod');
if (selectElement) {
setTimePeriod((selectElement as HTMLSelectElement).value);
}
}, []);
const handleNext = () => { const handleNext = () => {
setCurrentIndex((currentIndex + 1) % songs.length); setCurrentIndex((currentIndex + 1) % songs.length);
}; };
@ -68,10 +65,12 @@ export default function Home() {
</select> </select>
</div> </div>
{songs.length > 0 && ( {isLoading && <LoadingSpinner />}
{!isLoading && songs.length > 0 && (
<div className="relative"> <div className="relative">
<button onClick={handlePrevious} className="absolute left-0 top-1/2 transform -translate-y-1/2 text-gray-300"> <button onClick={handlePrevious} className="absolute left-0 top-1/2 transform -translate-y-1/2 text-gray-300">
<FontAwesomeIcon icon={faArrowLeft} size="2x" /> <ChevronLeft className="w-8 h-8" />
</button> </button>
<div className="text-center"> <div className="text-center">
@ -87,23 +86,24 @@ export default function Home() {
<p className="text-gray-300">{songs[currentIndex].duration}</p> <p className="text-gray-300">{songs[currentIndex].duration}</p>
<div className="mt-4"> <div className="mt-4">
<button className="mr-4 text-gray-300"> <button className="mr-4 text-gray-300">
<FontAwesomeIcon icon={faStepBackward} size="2x" /> <SkipBack className="w-8 h-8" />
</button> </button>
<button className="mr-4 text-gray-300" onClick={() => window.open(songs[currentIndex]?.link, '_blank')}> <button className="mr-4 text-gray-300" onClick={() => window.open(songs[currentIndex]?.link, '_blank')}>
<FontAwesomeIcon icon={faPlay} size="2x" /> <Play className="w-8 h-8" />
</button> </button>
<button className="text-gray-300"> <button className="text-gray-300">
<FontAwesomeIcon icon={faStepForward} size="2x" /> <SkipForward className="w-8 h-8" />
</button> </button>
</div> </div>
</div> </div>
<button onClick={handleNext} className="absolute right-0 top-1/2 transform -translate-y-1/2 text-gray-300"> <button onClick={handleNext} className="absolute right-0 top-1/2 transform -translate-y-1/2 text-gray-300">
<FontAwesomeIcon icon={faArrowRight} size="2x" /> <ChevronRight className="w-8 h-8" />
</button> </button>
</div> </div>
)} )}
</section> </section>
</div> </div>
); );
} }

View File

@ -1,32 +1,33 @@
import React from 'react'; import React from 'react';
import Link from 'next/link'; import MusicInfoButton from './MusicInfoButton';
interface TimePeriod {
title: string;
slug: string;
}
const timePeriods: TimePeriod[] = [
{ title: 'Late Summer 2024', slug: 'late-summer-2024' },
{ title: 'Early Summer 2024', slug: 'early-summer-2024' },
];
const MusicInfo: React.FC = () => { const MusicInfo: React.FC = () => {
return ( return (
<div className="max-w-2xl mx-auto text-center text-gray-200"> <div className="max-w-2xl mx-auto text-center text-gray-200">
<section className="mb-12"> {timePeriods.map((period) => (
<h2 className="text-2xl font-semibold mb-4">Late Summer 2024</h2> <section key={period.slug} className="mb-12">
<div className="flex justify-center space-x-4"> <h2 className="text-2xl font-semibold mb-4">{period.title}</h2>
<Link href="/time-periods/late-summer-2024/what-was-going-on" legacyBehavior> <div className="flex justify-center">
<a className="bg-gray-800 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded"> <MusicInfoButton
WHAT WAS GOING ON href={`/time-periods/${period.slug}/what-was-going-on`}
</a> label="WHAT WAS GOING ON"
</Link> />
</div> </div>
</section> </section>
))}
<section className="mb-12">
<h2 className="text-2xl font-semibold mb-4">Early Summer 2024</h2>
<div className="flex justify-center space-x-4">
<Link href="/time-periods/early-summer-2024/what-was-going-on" legacyBehavior>
<a className="bg-gray-800 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded">
WHAT WAS GOING ON
</a>
</Link>
</div>
</section>
</div> </div>
); );
}; };
export default MusicInfo; export default MusicInfo;

View File

@ -0,0 +1,20 @@
import React from 'react';
import Link from 'next/link';
interface MusicInfoButtonProps {
href: string;
label: string;
}
const MusicInfoButton: React.FC<MusicInfoButtonProps> = ({ href, label }) => {
return (
<Link
href={href}
className="inline-block bg-gray-800 text-white font-bold py-2 px-4 rounded shadow-md transition-all duration-300 ease-in-out hover:bg-gray-700 hover:shadow-lg hover:-translate-y-0.5 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-500"
>
{label}
</Link>
);
};
export default MusicInfoButton;

View File

@ -2,8 +2,28 @@ import type { NextConfig } from "next";
const nextConfig: NextConfig = { const nextConfig: NextConfig = {
images: { images: {
domains: ['lastfm.freetls.fastly.net', 'p0ntus.com', 'github-readme-stats.vercel.app'], remotePatterns: [
{
protocol: 'https',
hostname: 'lastfm.freetls.fastly.net',
port: '',
pathname: '/**',
},
{
protocol: 'https',
hostname: 'p0ntus.com',
port: '',
pathname: '/**',
},
{
protocol: 'https',
hostname: 'github-readme-stats.vercel.app',
port: '',
pathname: '/**',
},
],
}, },
}; };
export default nextConfig; export default nextConfig;

View File

@ -16,6 +16,7 @@
"@vercel/analytics": "^1.4.1", "@vercel/analytics": "^1.4.1",
"@vercel/speed-insights": "^1.1.0", "@vercel/speed-insights": "^1.1.0",
"geist": "^1.3.1", "geist": "^1.3.1",
"lucide-react": "^0.469.0",
"next": "15.1.3", "next": "15.1.3",
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^19.0.0" "react-dom": "^19.0.0"