add handling for non-github repos, fix hydration errors in header, use Link instead of <a>, move contact button to own component, migrate data folders, use music skip buttons for navigating songs on music by time, change icon in footer, update about page with gitea details, rename LastPlayed widget
This commit is contained in:
parent
28d0cb4d63
commit
4ea774cca5
@ -1,12 +1,12 @@
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import { faGithub } from '@fortawesome/free-brands-svg-icons'
|
||||
import { faHeart } from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
<footer className="bg-gray-800 py-6">
|
||||
<div className="container mx-auto px-4 text-center">
|
||||
<a href="https://github.com/ihatenodejs/aidxnCC" target="_blank" rel="noopener noreferrer" className="text-gray-400 hover:text-white transition-colors">
|
||||
<FontAwesomeIcon icon={faGithub} className="text-md mr-1" /> This website is free, open source and in the public domain.
|
||||
<a href="https://git.pontusmail.org/aidan/aidxnCC" target="_blank" rel="noopener noreferrer" className="text-gray-400 hover:text-white transition-colors">
|
||||
<FontAwesomeIcon icon={faHeart} className="text-md mr-1" /> This website is free, open source and in the public domain.
|
||||
</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
@ -14,12 +14,12 @@ interface NavItemProps {
|
||||
}
|
||||
|
||||
const NavItem = ({ href, icon, children }: NavItemProps) => (
|
||||
<li>
|
||||
<div className="nav-item">
|
||||
<Link href={href} className="flex items-center text-gray-300 hover:text-white hover:bg-gray-700 rounded-md px-3 py-2 transition-all duration-300">
|
||||
<FontAwesomeIcon icon={icon} className="text-md mr-2" />
|
||||
{children}
|
||||
</Link>
|
||||
</li>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default function Header() {
|
||||
@ -43,12 +43,12 @@ export default function Header() {
|
||||
<NavItem href="/domains" icon={faLink}>Domains</NavItem>
|
||||
<NavItem href="https://blog.aidxn.fun/" icon={faWordpressSimple}>Blog</NavItem>
|
||||
<NavItem href="/music" icon={faMusic}>Music by Time</NavItem>
|
||||
<li className="flex items-center">
|
||||
<div className="flex items-center">
|
||||
<NavItem href="https://tilde.club/~lxu" icon={faTerminal}>Tilde</NavItem>
|
||||
<a href="https://tilde.wiki/Tildeverse" className="text-gray-300 hover:text-green-400 ml-1 text-sm" target="_blank" rel="noopener noreferrer">
|
||||
<sup>what?</sup>
|
||||
</a>
|
||||
</li>
|
||||
</div>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
|
26
app/components/objects/ContactButton.tsx
Normal file
26
app/components/objects/ContactButton.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
import { IconDefinition } from '@fortawesome/fontawesome-svg-core'
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import Link from 'next/link';
|
||||
|
||||
interface ContactButtonProps {
|
||||
href: string;
|
||||
icon: IconDefinition;
|
||||
label: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
function ContactButton({ href, icon, label, className }: ContactButtonProps) {
|
||||
return (
|
||||
<Link
|
||||
href={href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className={`bg-gray-700 text-white px-4 py-2 rounded-full hover:bg-gray-600 transition-colors inline-flex items-center ${className}`}
|
||||
>
|
||||
<FontAwesomeIcon icon={icon} className="text-xl mr-2" />
|
||||
{label}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
export default ContactButton;
|
@ -2,9 +2,10 @@
|
||||
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import { faUser } from '@fortawesome/free-solid-svg-icons'
|
||||
import GitHubFeatured from '../widgets/GitHubFeatured'
|
||||
import FeaturedRepos from '../widgets/FeaturedRepos'
|
||||
import Image from 'next/image'
|
||||
import { useState } from 'react'
|
||||
import Link from 'next/link'
|
||||
|
||||
export default function About() {
|
||||
const [imageError, setImageError] = useState(false);
|
||||
@ -28,12 +29,13 @@ export default function About() {
|
||||
When I'm not programming, I can typically be found installing another Linux distro on my laptop or flashing a new ROM to my phone. I am also a passionate writer and I like to write creatively in my free time.
|
||||
</p>
|
||||
<p className="text-gray-300">
|
||||
I am almost always active on GitHub and make daily contributions to several of my repositories. I am a big fan of open source software and public domain software (which most of my repos are licensed under). In fact, the website you're currently on is free and open source. It's even under the public domain!
|
||||
I am almost always active on <Link href="https://git.pontusmail.org/" className="text-blue-400 hover:underline">my Gitea instance</Link> and GitHub and make daily contributions to several of my repositories. I am a big fan of open source software and public domain software (which most of my repos are licensed under). In fact, the website you're currently on is free and open source. It's even under the public domain!
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-12">
|
||||
<h2 className="text-2xl font-semibold mb-4 text-gray-200">My GitHub Contributions</h2>
|
||||
<p className="text-gray-300 mb-4">You can find me on GitHub as <a href="https://github.com/ihatenodejs/" className="text-blue-400 hover:underline">ihatenodejs</a>.</p>
|
||||
<h2 className="text-2xl font-semibold mb-4 text-gray-200">My Gitea/GitHub Contributions</h2>
|
||||
<p className="text-gray-300 mb-4">Most of my repositories have migrated to <Link href="https://git.pontusmail.org/" className="text-blue-400 hover:underline">LibreCloud Git</Link>. My username is <Link href="https://git.pontusmail.org/aidan/" className="text-blue-400 hover:underline">aidan</Link>.</p>
|
||||
<p className="text-gray-300 mb-4">You can find me on GitHub as <Link href="https://github.com/ihatenodejs/" className="text-blue-400 hover:underline">ihatenodejs</Link>.</p>
|
||||
{!imageError && (
|
||||
<div className="flex flex-col md:flex-row justify-center gap-4">
|
||||
<Image
|
||||
@ -63,8 +65,8 @@ export default function About() {
|
||||
</div>
|
||||
<div className="mt-12">
|
||||
<h2 className="text-2xl font-semibold mb-4 text-gray-200">Featured Projects</h2>
|
||||
<p className="text-gray-300 mb-6">Here's just four of my top projects.</p>
|
||||
<GitHubFeatured />
|
||||
<p className="text-gray-300 mb-6">Here's just four of my top projects. Star and fork counts are manually updated and count both Gitea and GitHub.</p>
|
||||
<FeaturedRepos />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import { faPhone, faEnvelope } from '@fortawesome/free-solid-svg-icons'
|
||||
import { faGithub, faTelegram } from '@fortawesome/free-brands-svg-icons'
|
||||
import { IconDefinition } from '@fortawesome/fontawesome-svg-core'
|
||||
import ContactButton from '../objects/ContactButton'
|
||||
|
||||
export default function Contact() {
|
||||
return (
|
||||
@ -35,24 +35,3 @@ export default function Contact() {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
interface ContactButtonProps {
|
||||
href: string;
|
||||
icon: IconDefinition;
|
||||
label: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
function ContactButton({ href, icon, label, className }: ContactButtonProps) {
|
||||
return (
|
||||
<a
|
||||
href={href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className={`bg-gray-700 text-white px-4 py-2 rounded-full hover:bg-gray-600 transition-colors inline-flex items-center ${className}`}
|
||||
>
|
||||
<FontAwesomeIcon icon={icon} className="text-xl mr-2" />
|
||||
{label}
|
||||
</a>
|
||||
)
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import { faLink } from '@fortawesome/free-solid-svg-icons'
|
||||
import domains from '../../data/domains.json'
|
||||
import domains from '../../../public/data/domains.json'
|
||||
|
||||
export default function About() {
|
||||
return (
|
||||
|
@ -40,6 +40,9 @@ export default function Home() {
|
||||
<p className="text-gray-300 leading-relaxed mt-2">
|
||||
I'm most proud of LibreCloud/p0ntus mail, which is a cloud services provider that I self-host and maintain, free of charge.
|
||||
</p>
|
||||
<p className="text-gray-300 leading-relaxed mt-2">
|
||||
I frequently write and work on a website hosted on a public Linux server, called a "tilde." You can check it out by clicking the link "Tilde" in the header, or "what?" if you are still confused!
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section id="contact">
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||
import { faGithub } from '@fortawesome/free-brands-svg-icons'
|
||||
import { faGitAlt, faGithub } from '@fortawesome/free-brands-svg-icons'
|
||||
import { faStar, faCodeBranch } from '@fortawesome/free-solid-svg-icons'
|
||||
import featuredProjects from '../../data/featured.json'
|
||||
import featuredProjects from '../../../public/data/featured.json'
|
||||
import Link from 'next/link'
|
||||
|
||||
export default function GitHubFeatured() {
|
||||
return (
|
||||
@ -10,12 +11,12 @@ export default function GitHubFeatured() {
|
||||
<div key={project.id} className="bg-gray-800 p-6 rounded-lg shadow-md min-h-[200px] flex flex-col">
|
||||
<div className="flex-1">
|
||||
<h3 className="text-xl font-bold text-gray-100 mb-3">
|
||||
<FontAwesomeIcon icon={faGithub} className="mr-2" /> {project.name}
|
||||
<FontAwesomeIcon icon={project.github ? faGithub : faGitAlt} className="mr-2" /> {project.name}
|
||||
</h3>
|
||||
<p className="text-gray-300 flex-grow">{project.description}</p>
|
||||
</div>
|
||||
<div className="pt-4 border-t border-gray-700 flex justify-between items-center mt-auto">
|
||||
<a href={project.url} className="text-blue-400 hover:underline">View Repo</a>
|
||||
<Link href={project.url} className="text-blue-400 hover:underline">View Repo</Link>
|
||||
<div className="flex items-center text-gray-400">
|
||||
<FontAwesomeIcon icon={faStar} className="mr-1" /> {project.stars}
|
||||
<FontAwesomeIcon icon={faCodeBranch} className="ml-4 mr-1" /> {project.forks}
|
@ -15,7 +15,7 @@ interface Track {
|
||||
'@attr'?: { nowplaying: string };
|
||||
}
|
||||
|
||||
const NowPlaying: React.FC = () => {
|
||||
const LastPlayed: React.FC = () => {
|
||||
const [track, setTrack] = useState<Track | null>(null);
|
||||
const apiUrl = process.env.LASTFM_API_URL || 'https://lastfm-last-played.biancarosa.com.br/aidxn_/latest-song';
|
||||
|
||||
@ -29,7 +29,7 @@ const NowPlaying: React.FC = () => {
|
||||
if (!track) {
|
||||
return (
|
||||
<div className="max-w-2xl mx-auto mt-4">
|
||||
<h2 className="text-2xl font-bold mb-4 pt-10 text-gray-200">Music</h2>
|
||||
<h2 className="text-2xl font-bold mb-4 pt-10 text-gray-200">Last Played Song</h2>
|
||||
<div className="flex justify-center items-center border border-gray-300 rounded-lg p-4 max-w-md mt-8">
|
||||
<span className="spinner-border animate-spin inline-block w-8 h-8 border-4 rounded-full" role="status"></span>
|
||||
</div>
|
||||
@ -39,7 +39,7 @@ const NowPlaying: React.FC = () => {
|
||||
|
||||
return (
|
||||
<div className="max-w-2xl mx-auto mt-4">
|
||||
<h2 className="text-2xl font-bold mb-4 pt-10 text-gray-200">Music</h2>
|
||||
<h2 className="text-2xl font-bold mb-4 pt-10 text-gray-200">Last Played Song</h2>
|
||||
<div className="now-playing flex items-center border border-gray-300 rounded-lg p-4 max-w-md mt-8 bg-white bg-opacity-10 backdrop-filter backdrop-blur-lg">
|
||||
<Image
|
||||
src={track.image.find(img => img.size === 'large')?.['#text'] || '/placeholder.png'}
|
||||
@ -61,4 +61,4 @@ const NowPlaying: React.FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default NowPlaying;
|
||||
export default LastPlayed;
|
@ -2,7 +2,7 @@
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
import Image from 'next/image';
|
||||
import { Play, SkipBack, SkipForward, ChevronLeft, ChevronRight } from 'lucide-react';
|
||||
import { Play, SkipBack, SkipForward } from 'lucide-react';
|
||||
import LoadingSpinner from '../objects/LoadingSpinner';
|
||||
|
||||
interface Song {
|
||||
@ -19,7 +19,7 @@ interface Period {
|
||||
}
|
||||
|
||||
export default function Home() {
|
||||
const [timePeriod, setTimePeriod] = useState('Summer 2024');
|
||||
const [timePeriod, setTimePeriod] = useState('Early Summer 2024');
|
||||
const [songs, setSongs] = useState<Song[]>([]);
|
||||
const [currentIndex, setCurrentIndex] = useState(0);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
@ -61,7 +61,7 @@ export default function Home() {
|
||||
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>
|
||||
<option value="Early Summer 2024">Early Summer 2024</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@ -69,10 +69,6 @@ export default function Home() {
|
||||
|
||||
{!isLoading && songs.length > 0 && (
|
||||
<div className="relative">
|
||||
<button onClick={handlePrevious} className="absolute left-0 top-1/2 transform -translate-y-1/2 text-gray-300">
|
||||
<ChevronLeft className="w-8 h-8" />
|
||||
</button>
|
||||
|
||||
<div className="text-center">
|
||||
<Image
|
||||
src={songs[currentIndex].albumArt}
|
||||
@ -85,21 +81,17 @@ export default function Home() {
|
||||
<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">
|
||||
<button onClick={handlePrevious} className="mr-4 text-gray-300">
|
||||
<SkipBack className="w-8 h-8" />
|
||||
</button>
|
||||
<button className="mr-4 text-gray-300" onClick={() => window.open(songs[currentIndex]?.link, '_blank')}>
|
||||
<Play className="w-8 h-8" />
|
||||
</button>
|
||||
<button className="text-gray-300">
|
||||
<button onClick={handleNext} className="text-gray-300">
|
||||
<SkipForward className="w-8 h-8" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button onClick={handleNext} className="absolute right-0 top-1/2 transform -translate-y-1/2 text-gray-300">
|
||||
<ChevronRight className="w-8 h-8" />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import Header from './components/Header';
|
||||
import HomePg from './components/pages/Home';
|
||||
import Footer from './components/Footer';
|
||||
import NowPlaying from './components/widgets/NowPlaying';
|
||||
import LastPlayed from './components/widgets/LastPlayed';
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
@ -9,7 +9,7 @@ export default function Home() {
|
||||
<Header />
|
||||
<main className="flex-grow container mx-auto px-4 py-12">
|
||||
<HomePg />
|
||||
<NowPlaying />
|
||||
<LastPlayed />
|
||||
</main>
|
||||
<Footer />
|
||||
</div>
|
||||
|
@ -3,32 +3,36 @@
|
||||
"id": 1,
|
||||
"name": "aidxnCC",
|
||||
"description": "aidxnCC is the third version of my personal website",
|
||||
"url": "https://github.com/ihatenodejs/aidxnCC",
|
||||
"stars": 1,
|
||||
"github": false,
|
||||
"url": "https://git.pontusmail.org/aidan/aidxnCC",
|
||||
"stars": 2,
|
||||
"forks": 1
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "pontus-mail",
|
||||
"description": "Landing page for p0ntus mail",
|
||||
"url": "https://github.com/ihatenodejs/pontus-mail",
|
||||
"stars": 7,
|
||||
"github": false,
|
||||
"url": "https://git.pontusmail.org/aidan/pontus-mail",
|
||||
"stars": 8,
|
||||
"forks": 0
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "modules",
|
||||
"description": "An open-source Magisk module and FOSS app store",
|
||||
"url": "https://github.com/ihatenodejs/modules",
|
||||
"stars": 2,
|
||||
"github": false,
|
||||
"url": "https://git.pontusmail.org/aidan/modules",
|
||||
"stars": 3,
|
||||
"forks": 0
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "AndroidIntegrity/website",
|
||||
"description": "AIA website source code",
|
||||
"github": true,
|
||||
"url": "https://github.com/AndroidIntegrity/website",
|
||||
"stars": 5,
|
||||
"stars": 6,
|
||||
"forks": 1
|
||||
}
|
||||
]
|
@ -1,63 +1,56 @@
|
||||
[
|
||||
{
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"albumArt": "https://p0ntus.com/archives/img/nani.webp",
|
||||
"name": "NANi",
|
||||
"artist": "Saweetie",
|
||||
"duration": "2:34",
|
||||
"link": "https://www.last.fm/music/Saweetie/Nani"
|
||||
},
|
||||
{
|
||||
"albumArt": "https://p0ntus.com/archives/img/nani.webp",
|
||||
"name": "NANi",
|
||||
"artist": "Saweetie",
|
||||
"duration": "2:34",
|
||||
"link": "https://www.last.fm/music/Saweetie/Nani"
|
||||
},
|
||||
{
|
||||
"albumArt": "https://p0ntus.com/archives/img/killerloverboy.webp",
|
||||
"name": "killer lover boy",
|
||||
"artist": "SEB",
|
||||
"duration": "2:14",
|
||||
"link": "https://www.last.fm/music/Seb/_/killer+lover+boy"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
{
|
||||
"timePeriod": "Early 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"
|
||||
},
|
||||
{
|
||||
"albumArt": "https://p0ntus.com/archives/img/nani.webp",
|
||||
"name": "NANi",
|
||||
"artist": "Saweetie",
|
||||
"duration": "2:34",
|
||||
"link": "https://www.last.fm/music/Saweetie/Nani"
|
||||
},
|
||||
{
|
||||
"albumArt": "https://p0ntus.com/archives/img/killerloverboy.webp",
|
||||
"name": "killer lover boy",
|
||||
"artist": "SEB",
|
||||
"duration": "2:14",
|
||||
"link": "https://www.last.fm/music/Seb/_/killer+lover+boy"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
Loading…
x
Reference in New Issue
Block a user