add radio page

This commit is contained in:
Alex Frantz
2024-04-22 02:03:14 -04:00
parent dd60999e3a
commit 50f793de74
8 changed files with 142 additions and 16 deletions
+4 -4
View File
@@ -18,7 +18,7 @@
"@trpc/react-query": "^10.37.1", "@trpc/react-query": "^10.37.1",
"@trpc/server": "^10.37.1", "@trpc/server": "^10.37.1",
"axios": "^1.6.2", "axios": "^1.6.2",
"grommet-icons": "^4.11.0", "grommet-icons": "^4.12.1",
"next": "^13.5.4", "next": "^13.5.4",
"next-auth": "^4.23.0", "next-auth": "^4.23.0",
"react": "18.2.0", "react": "18.2.0",
@@ -2729,9 +2729,9 @@
"dev": true "dev": true
}, },
"node_modules/grommet-icons": { "node_modules/grommet-icons": {
"version": "4.11.0", "version": "4.12.1",
"resolved": "https://registry.npmjs.org/grommet-icons/-/grommet-icons-4.11.0.tgz", "resolved": "https://registry.npmjs.org/grommet-icons/-/grommet-icons-4.12.1.tgz",
"integrity": "sha512-ArXf2XyXmpk5JsQ8NudzNz3mbWv+TeZkPiyog2s9yoNAWTlIr3vzNjr97uon/Xm4Uiq2kiHkvO4i2fG1u6EaDg==", "integrity": "sha512-LhOP6BkDAGiSNcUOfsGGRo+AKD6zWOXeNeusY1WYvKplAR6mKCAQfH7Nig2Buc/v5zadKSko2NDtCQqwJaME0Q==",
"peerDependencies": { "peerDependencies": {
"react": "^16.6.0 || ^17.0.0 || ^18.0.0", "react": "^16.6.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.6.0 || ^17.0.0 || ^18.0.0", "react-dom": "^16.6.0 || ^17.0.0 || ^18.0.0",
+1 -1
View File
@@ -21,7 +21,7 @@
"@trpc/react-query": "^10.37.1", "@trpc/react-query": "^10.37.1",
"@trpc/server": "^10.37.1", "@trpc/server": "^10.37.1",
"axios": "^1.6.2", "axios": "^1.6.2",
"grommet-icons": "^4.11.0", "grommet-icons": "^4.12.1",
"next": "^13.5.4", "next": "^13.5.4",
"next-auth": "^4.23.0", "next-auth": "^4.23.0",
"react": "18.2.0", "react": "18.2.0",
+1 -1
View File
@@ -1,7 +1,7 @@
export default function Footer() { export default function Footer() {
return ( return (
<> <>
<div className="relative rounded-t-sm p-2 text-white opacity-50"> <div className="absolute bottom-0 rounded-t-sm p-2 text-white opacity-50">
<p className="text-center"> <p className="text-center">
The &apos;PipBoy&apos; is owned by Bethesda, I&apos;m just doing this for fun! The &apos;PipBoy&apos; is owned by Bethesda, I&apos;m just doing this for fun!
</p> </p>
+3 -2
View File
@@ -9,14 +9,15 @@ export default function Header({
}: HeaderProps) { }: HeaderProps) {
return ( return (
<> <>
<div className="text-white max-w-sm mx-auto pt-2 pb-4"> <div className="text-white max-w-md mx-auto pt-2 pb-4 text-center">
<div className="inline-block pb-2 space-x-6 text-center"> <div className="inline-block pb-2 space-x-6">
<HeaderItem content="HOME" linkTo={ <HeaderItem content="HOME" linkTo={
isNotHomePage ? "/?noAnimation" isNotHomePage ? "/?noAnimation"
: "/" : "/"
} /> } />
<HeaderItem content="LINKS" linkTo="/links" /> <HeaderItem content="LINKS" linkTo="/links" />
<HeaderItem content="PROJECTS" linkTo="/projects" /> <HeaderItem content="PROJECTS" linkTo="/projects" />
<HeaderItem content="RADIO" linkTo="/radio" />
<HeaderItem content="ABOUT" linkTo="/about" /> <HeaderItem content="ABOUT" linkTo="/about" />
</div> </div>
<hr className="border-green-500" /> <hr className="border-green-500" />
+39 -7
View File
@@ -2,25 +2,57 @@ import RootLayout from "@/components/RootLayout";
import Footer from "@/components/footer"; import Footer from "@/components/footer";
import Header from "@/components/header"; import Header from "@/components/header";
import Link from "next/link"; import Link from "next/link";
import {useState} from 'react';
// icons
import {
Twitter,
MailOption
} from 'grommet-icons'
export default function LinksPage() { export default function LinksPage() {
const [icon, setIcon] = useState<Element | null>();
return ( return (
<RootLayout> <RootLayout>
<Header isNotHomePage={true} /> <Header isNotHomePage={true} />
<div className="text-green-500 text-center"> <div className="text-green-500 max-h-96">
<h1 className="font-bold text-3xl">My Links!</h1> <h1 className="font-bold text-3xl ml-2">My Links!</h1>
<div className="space-y-2"> <div className="space-y-2 float-left">
<Link href="https://twitter.com/avvex__" target="_blank"> <Link
href="https://twitter.com/avvex__"
target="_blank"
onMouseOver={() => {
setIcon(<Twitter size="large" />)
}}
onMouseLeave={() => {
setIcon(null)
}}
>
<div className="hover:bg-green-500 hover:text-black"> <div className="hover:bg-green-500 hover:text-black">
<h1 className="text-2xl mx-32">Twitter</h1> <h1 className="text-2xl mr-32 ml-2">Twitter</h1>
</div> </div>
</Link> </Link>
<Link href="https://mast.thatalex.dev/@alex" target="_blank"> <Link
href="https://mast.thatalex.dev/@alex"
target="_blank"
onMouseOver={() => {
setIcon(<MailOption size="large" />)
}}
onMouseLeave={() => {
setIcon(null)
}}
>
<div className="hover:bg-green-500 hover:text-black"> <div className="hover:bg-green-500 hover:text-black">
<h1 className="text-2xl mx-32">Mastodon</h1> <h1 className="text-2xl mr-32 ml-2">Mastodon</h1>
</div> </div>
</Link> </Link>
</div> </div>
<div className="float-right">
{/* <Twitter size='xlarge' className="mr-24" /> */}
{icon}
</div>
</div> </div>
<Footer /> <Footer />
</RootLayout> </RootLayout>
+47
View File
@@ -0,0 +1,47 @@
import RootLayout from "@/components/RootLayout";
import Footer from "@/components/footer";
import Header from "@/components/header";
import { api } from "@/utils/api";
// next components
import Link from 'next/link';
import Image from "next/image";
export default function MusicPage() {
const { data: musicData, fetchStatus} = api.misc.song.useQuery();
return (
<RootLayout>
<Header isNotHomePage={true} />
<div className="text-green-500 flicker max-w-1/2">
<div className="float-left">
{
fetchStatus === "idle" ?
musicData?.data.tracks.map((v,k) => {
return <div key={k}>
<div className={`text-lg ${k === 0 ? "bg-green-500 text-black" : "hover:bg-green-500 hover:text-black"}`}>
<Link href={v.url} target="_blank">
<h1 className="ml-2 mr-36 truncate max-w-10">{k === 0 && "■"} {v.name}</h1>
</Link>
</div>
</div>
})
: <h1 className="font-bold text-green-500">Fetching..</h1>
}
</div>
<div className="float-right">
{
fetchStatus === "idle" &&
<Image
src={musicData?.data.tracks[0]?.image[2]?.["#text"] ?? "https://storage.thatalex.dev"}
alt="Cover Art"
width="160"
height="160"
/>
}
</div>
</div>
<Footer />
</RootLayout>
)
}
+3 -1
View File
@@ -1,6 +1,7 @@
import { postRouter } from "@/server/api/routers/post"; import { postRouter } from "@/server/api/routers/post";
import { linksRouter } from "./routers/links"; import { linksRouter } from "./routers/links";
import { blogRouter } from "./routers/blog"; import { blogRouter } from "./routers/blog";
import { miscRouter } from "./routers/misc";
import { createTRPCRouter } from "@/server/api/trpc"; import { createTRPCRouter } from "@/server/api/trpc";
/** /**
@@ -11,7 +12,8 @@ import { createTRPCRouter } from "@/server/api/trpc";
export const appRouter = createTRPCRouter({ export const appRouter = createTRPCRouter({
post: postRouter, post: postRouter,
links: linksRouter, links: linksRouter,
blog: blogRouter blog: blogRouter,
misc: miscRouter
}); });
// export type definition of API // export type definition of API
+44
View File
@@ -0,0 +1,44 @@
import axios from 'axios';
import {
createTRPCRouter,
publicProcedure
} from '@/server/api/trpc';
type ImageListType = {
"size": string,
"#text": string
}
type TrackResponseType = {
status: number,
data: {
tracks: LastTrackType[]
}
}
type LastTrackType = {
"@attr": {
"nowplaying": string
},
"album": {
"mbid": string,
"#text": string
},
"artist": {
"mbid": string,
"#text": string,
},
"image": ImageListType[],
"mbid": string,
"name": string,
"streamable": number,
"url": string
}
export const miscRouter = createTRPCRouter({
song: publicProcedure
.query(async () => {
const response = await axios.get<TrackResponseType>("https://api.thatalex.dev/v4/social/music")
return response.data
}),
})