implement music by time period, clean up header
This commit is contained in:
parent
4b88c00919
commit
37d478d9b8
@ -1,17 +1,17 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState } from 'react'
|
import { useState } from 'react';
|
||||||
import Link from 'next/link'
|
import Link from 'next/link';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { faWordpressSimple } from '@fortawesome/free-brands-svg-icons'
|
import { faWordpressSimple } from '@fortawesome/free-brands-svg-icons';
|
||||||
import { faLink, faHouse, faUser, faPhone, faBars, faTimes, faTerminal } from '@fortawesome/free-solid-svg-icons'
|
import { faLink, faHouse, faUser, faPhone, faBars, faTimes, faTerminal, faMusic } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
export default function Header() {
|
export default function Header() {
|
||||||
const [isOpen, setIsOpen] = useState(false)
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
const toggleMenu = () => {
|
const toggleMenu = () => {
|
||||||
setIsOpen(!isOpen)
|
setIsOpen(!isOpen);
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="bg-gray-800">
|
<header className="bg-gray-800">
|
||||||
@ -28,6 +28,7 @@ export default function Header() {
|
|||||||
<li><Link href="/contact" className="flex items-center text-gray-300 hover:text-white hover:bg-gray-700 rounded-md px-3 py-2 transition-all"><FontAwesomeIcon icon={faPhone} className="text-md mr-2" /> Contact</Link></li>
|
<li><Link href="/contact" className="flex items-center text-gray-300 hover:text-white hover:bg-gray-700 rounded-md px-3 py-2 transition-all"><FontAwesomeIcon icon={faPhone} className="text-md mr-2" /> Contact</Link></li>
|
||||||
<li><Link href="/domains" className="flex items-center text-gray-300 hover:text-white hover:bg-gray-700 rounded-md px-3 py-2 transition-all"><FontAwesomeIcon icon={faLink} className="text-md mr-2" /> Domains</Link></li>
|
<li><Link href="/domains" className="flex items-center text-gray-300 hover:text-white hover:bg-gray-700 rounded-md px-3 py-2 transition-all"><FontAwesomeIcon icon={faLink} className="text-md mr-2" /> Domains</Link></li>
|
||||||
<li><Link href="https://blog.aidxn.fun/" className="flex items-center text-gray-300 hover:text-white hover:bg-gray-700 rounded-md px-3 py-2 transition-all"><FontAwesomeIcon icon={faWordpressSimple} className="text-md mr-2" /> Blog</Link></li>
|
<li><Link href="https://blog.aidxn.fun/" className="flex items-center text-gray-300 hover:text-white hover:bg-gray-700 rounded-md px-3 py-2 transition-all"><FontAwesomeIcon icon={faWordpressSimple} className="text-md mr-2" /> Blog</Link></li>
|
||||||
|
<li><Link href="/music" className="flex items-center text-gray-300 hover:text-white hover:bg-gray-700 rounded-md px-3 py-2 transition-all"><FontAwesomeIcon icon={faMusic} className="text-md mr-2" /> Music by Time</Link></li>
|
||||||
<li className="flex items-center">
|
<li className="flex items-center">
|
||||||
<Link href="https://tilde.club/~lxu" className="flex items-center text-gray-300 hover:text-white hover:bg-gray-700 rounded-md px-3 py-2 transition-all">
|
<Link href="https://tilde.club/~lxu" className="flex items-center text-gray-300 hover:text-white hover:bg-gray-700 rounded-md px-3 py-2 transition-all">
|
||||||
<FontAwesomeIcon icon={faTerminal} className="text-md mr-2" /> Tilde
|
<FontAwesomeIcon icon={faTerminal} className="text-md mr-2" /> Tilde
|
||||||
@ -39,5 +40,5 @@ export default function Header() {
|
|||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
)
|
);
|
||||||
}
|
}
|
93
app/components/Music.tsx
Normal file
93
app/components/Music.tsx
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import Image from 'next/image';
|
||||||
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
|
import { faPlay, faStepBackward, faStepForward, faArrowLeft, faArrowRight } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
|
export default function Home() {
|
||||||
|
const [timePeriod, setTimePeriod] = useState('2020s');
|
||||||
|
const [songs, setSongs] = useState([]);
|
||||||
|
const [currentIndex, setCurrentIndex] = useState(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetch('/data/music.json')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
const selectedPeriod = data.find(period => period.timePeriod === timePeriod);
|
||||||
|
const songsList = selectedPeriod ? selectedPeriod.songs : [];
|
||||||
|
setSongs(songsList);
|
||||||
|
setCurrentIndex(Math.floor(Math.random() * songsList.length));
|
||||||
|
});
|
||||||
|
}, [timePeriod]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const selectElement = document.getElementById('timePeriod');
|
||||||
|
if (selectElement) {
|
||||||
|
setTimePeriod(selectElement.value);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleNext = () => {
|
||||||
|
setCurrentIndex((currentIndex + 1) % songs.length);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePrevious = () => {
|
||||||
|
setCurrentIndex((currentIndex - 1 + songs.length) % songs.length);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="max-w-2xl mx-auto">
|
||||||
|
<section id="music-carousel" className="mb-12">
|
||||||
|
<h2 className="text-3xl font-semibold mb-4 text-gray-200">Music By Time Period</h2>
|
||||||
|
<div className="mb-4 pb-4">
|
||||||
|
<label htmlFor="timePeriod" className="text-gray-300">Time Period:</label>
|
||||||
|
<select
|
||||||
|
id="timePeriod"
|
||||||
|
value={timePeriod}
|
||||||
|
onChange={(e) => setTimePeriod(e.target.value)}
|
||||||
|
className="ml-2 p-2 bg-gray-700 text-gray-300 rounded"
|
||||||
|
>
|
||||||
|
<option value="Summer 2024">Summer 2024</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{songs.length > 0 && (
|
||||||
|
<div className="relative">
|
||||||
|
<button onClick={handlePrevious} className="absolute left-0 top-1/2 transform -translate-y-1/2 text-gray-300">
|
||||||
|
<FontAwesomeIcon icon={faArrowLeft} size="2x" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div className="text-center">
|
||||||
|
<Image
|
||||||
|
src={songs[currentIndex].albumArt}
|
||||||
|
alt={songs[currentIndex].name}
|
||||||
|
width={300}
|
||||||
|
height={300}
|
||||||
|
className="mx-auto mb-4 rounded-lg"
|
||||||
|
/>
|
||||||
|
<h3 className="text-2xl font-bold text-gray-100">{songs[currentIndex].name}</h3>
|
||||||
|
<p className="text-gray-300">{songs[currentIndex].artist}</p>
|
||||||
|
<p className="text-gray-300">{songs[currentIndex].duration}</p>
|
||||||
|
<div className="mt-4">
|
||||||
|
<button className="mr-4 text-gray-300">
|
||||||
|
<FontAwesomeIcon icon={faStepBackward} size="2x" />
|
||||||
|
</button>
|
||||||
|
<button className="mr-4 text-gray-300" onClick={() => window.open(songs[currentIndex]?.link, '_blank')}>
|
||||||
|
<FontAwesomeIcon icon={faPlay} size="2x" />
|
||||||
|
</button>
|
||||||
|
<button className="text-gray-300">
|
||||||
|
<FontAwesomeIcon icon={faStepForward} size="2x" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button onClick={handleNext} className="absolute right-0 top-1/2 transform -translate-y-1/2 text-gray-300">
|
||||||
|
<FontAwesomeIcon icon={faArrowRight} size="2x" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
15
app/music/page.tsx
Normal file
15
app/music/page.tsx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import Header from '../components/Header'
|
||||||
|
import MusicWidget from '../components/Music'
|
||||||
|
import Footer from '../components/Footer'
|
||||||
|
|
||||||
|
export default function Music() {
|
||||||
|
return (
|
||||||
|
<div className="min-h-screen flex flex-col">
|
||||||
|
<Header />
|
||||||
|
<main className="flex-grow container mx-auto px-4 py-12">
|
||||||
|
<MusicWidget />
|
||||||
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -2,7 +2,7 @@ import type { NextConfig } from "next";
|
|||||||
|
|
||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
images: {
|
images: {
|
||||||
domains: ['lastfm.freetls.fastly.net'],
|
domains: ['lastfm.freetls.fastly.net', 'p0ntus.com'],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
42
public/data/music.json
Normal file
42
public/data/music.json
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"timePeriod": "Summer 2024",
|
||||||
|
"songs": [
|
||||||
|
{
|
||||||
|
"albumArt": "https://p0ntus.com/archives/img/noticeme.png",
|
||||||
|
"name": "Notice Me",
|
||||||
|
"artist": "tobi lou feat. MIA GLADSTONE",
|
||||||
|
"duration": "2:35",
|
||||||
|
"link": "https://www.last.fm/music/tobi+lou/Notice+Me"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"albumArt": "https://p0ntus.com/archives/img/comforttexas.webp",
|
||||||
|
"name": "comfort, texas",
|
||||||
|
"artist": "Buppy.",
|
||||||
|
"duration": "2:11",
|
||||||
|
"link": "https://www.last.fm/music/Buppy./comfort,+texas"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"albumArt": "https://p0ntus.com/archives/img/nonperishable.webp",
|
||||||
|
"name": "Jelly",
|
||||||
|
"artist": "tobi lou",
|
||||||
|
"duration": "1:50",
|
||||||
|
"link": "https://www.last.fm/music/tobi+lou/_/Jelly"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"albumArt": "https://p0ntus.com/archives/img/exes.webp",
|
||||||
|
"name": "exes",
|
||||||
|
"artist": "Tate McRae",
|
||||||
|
"duration": "2:39",
|
||||||
|
"link": "https://www.last.fm/music/Tate+McRae/exes/exes"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"albumArt": "https://p0ntus.com/archives/img/ick.webp",
|
||||||
|
"name": "Ick",
|
||||||
|
"artist": "Lay Bankz",
|
||||||
|
"duration": "1:55",
|
||||||
|
"link": "https://www.last.fm/music/Lay+Bankz/_/Ick"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
Reference in New Issue
Block a user