pip :)
This commit is contained in:
@@ -1,30 +1,29 @@
|
||||
import Link from "next/link"
|
||||
import type { MouseEventHandler } from "react"
|
||||
|
||||
type HeaderItemProps = {
|
||||
content: string,
|
||||
linkTo: string,
|
||||
onClick?: MouseEventHandler<HTMLButtonElement>, // don't even wanna bother
|
||||
newWindow?: boolean
|
||||
}
|
||||
export default function HeaderItem(props: HeaderItemProps) {
|
||||
if (props.onClick) {
|
||||
return (
|
||||
<>
|
||||
<button className="inline hover:text-gray-500 hover:underline pr-2 "
|
||||
onClick={props.onClick}
|
||||
>
|
||||
{props.content}
|
||||
</button>
|
||||
</>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<p className="inline pr-2 hover:text-gray-500 hover:underline">
|
||||
<Link href={props.linkTo} target={props.newWindow ? "_blank" : "_self"}>
|
||||
{props.content}
|
||||
</Link>
|
||||
</p>
|
||||
)
|
||||
}
|
||||
export default function HeaderItem({
|
||||
content,
|
||||
linkTo,
|
||||
newWindow
|
||||
}: HeaderItemProps) {
|
||||
return (
|
||||
<Link
|
||||
className="inline text-green-500 hover:underline font-bold text-3xl pr-2"
|
||||
href={linkTo}
|
||||
target={newWindow ? "_blank" : "_self"}
|
||||
>
|
||||
{content}
|
||||
</Link>
|
||||
// <>
|
||||
// <button className="inline text-green-500 hover:underline font-bold text-3xl pr-2"
|
||||
// onClick={props.onClick}
|
||||
// >
|
||||
// {props.content}
|
||||
// </button>
|
||||
// </>
|
||||
)
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
type InputOptionProps = {
|
||||
label: string,
|
||||
inputName: string,
|
||||
isTextArea?: boolean
|
||||
}
|
||||
|
||||
export default function InputOption(props: InputOptionProps) {
|
||||
return (
|
||||
<div className="pt-2 pb-2">
|
||||
<label className="font-bold">{props.label}</label><br />
|
||||
{
|
||||
props.isTextArea ?
|
||||
<textarea className="bg-gray-800 rounded-sm text-white resize-none h-32 w-72" name={props.inputName} />
|
||||
:
|
||||
<input className="bg-gray-800 rounded-sm text-white" name={props.inputName} />
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { api } from "@/utils/api";
|
||||
|
||||
export default function MusicCard() {
|
||||
const {data: musicData, fetchStatus} = api.misc.song.useQuery()
|
||||
|
||||
return (
|
||||
<div className="bg-white text-black max-w-fit mx-auto p-4">
|
||||
<h1 className="text-2xl font-bold inline">Listening To</h1>
|
||||
|
||||
{/* link to lastfm */}
|
||||
<Link
|
||||
href="https://last.fm/user/lulawex"
|
||||
target="_blank"
|
||||
className="opacity-75 underline font-bold text-sm ml-2 hover:text-zinc-600"
|
||||
>
|
||||
Powered by Last.fm
|
||||
</Link>
|
||||
|
||||
{
|
||||
fetchStatus !== "fetching" ?
|
||||
<div className="space-y-2">
|
||||
{
|
||||
musicData?.track.map((v,k) => {
|
||||
return <div key={k}>
|
||||
<Image
|
||||
src={v.image[0]?.["#text"] ?? "https://storage.thatalex.dev/content/pfp.jpg"}
|
||||
width="50"
|
||||
height="50"
|
||||
alt={`${v.name} Cover Art`}
|
||||
className="inline mr-2"
|
||||
/>
|
||||
<div className="inline-block align-middle">
|
||||
<Link href={v.url} target="_blank">
|
||||
<h1 className="font-bold w-52 truncate hover:underline">{v.name}</h1>
|
||||
</Link>
|
||||
<p className="opacity-75">{v.artist["#text"]}</p>
|
||||
</div>
|
||||
</div>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
:
|
||||
<p className="font-bold">Hold tight, fetching..</p>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<div className="text-white text-center">
|
||||
<h1 className="font-bold text-2xl">Well, this is awkward..</h1>
|
||||
<p>There's nothing here right now :/</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
import Link from "next/link"
|
||||
|
||||
type ProjectCardProps = {
|
||||
name: string,
|
||||
technologies: string[],
|
||||
subHeading?: string,
|
||||
description: string,
|
||||
urlTo: string
|
||||
}
|
||||
|
||||
export default function ProjectCard(props: ProjectCardProps) {
|
||||
const technologies = props.technologies.map((v,k) => {
|
||||
return <div key={k} className="inline">
|
||||
<div className="max-w-fit p-1 inline">
|
||||
{v}
|
||||
</div>
|
||||
</div>
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="bg-zinc-700 max-w-lg">
|
||||
<div className="p-2 space-y-2 space-x-2">
|
||||
<h1 className="font-bold text-2xl inline pl-2">{props.name}</h1>
|
||||
<div className="inline-block">
|
||||
{technologies}
|
||||
</div>
|
||||
<hr className="max-w-xs" />
|
||||
<p>{props.description}</p>
|
||||
|
||||
<div className="bg-zinc-900 max-w-fit p-2 rounded-lg">
|
||||
<Link href={props.urlTo} target="_blank">
|
||||
<p>Source</p>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import Image from "next/image"
|
||||
import Link from 'next/link';
|
||||
|
||||
type ReviewCardProps = {
|
||||
title: string,
|
||||
image: string,
|
||||
url: string,
|
||||
showText: boolean
|
||||
}
|
||||
|
||||
export default function ReviewCard(props: ReviewCardProps) {
|
||||
return (
|
||||
<Link href={props.url}>
|
||||
<div className="inline">
|
||||
<Image alt={props.title + " cover"} width="160" height="160" src={props.image} className="p-2" />
|
||||
{
|
||||
props.showText ?
|
||||
<p className="font-bold pt-2 text-center">{props.title}</p>
|
||||
:
|
||||
""
|
||||
}
|
||||
</div>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
@@ -1,51 +1,21 @@
|
||||
// component imports
|
||||
import Header from "./header";
|
||||
import Footer from "./footer";
|
||||
import Head from "./Head"
|
||||
|
||||
// react imports
|
||||
import React from 'react';
|
||||
|
||||
// next modules
|
||||
import { useSession } from "next-auth/react";
|
||||
import Router from 'next/router';
|
||||
|
||||
type LayoutProps = {
|
||||
children: React.ReactNode
|
||||
protectedPage?: boolean
|
||||
}
|
||||
|
||||
export default function RootLayout({ children, protectedPage }: LayoutProps) {
|
||||
const {status} = useSession()
|
||||
|
||||
if (protectedPage) {
|
||||
if (status === "loading") {
|
||||
return (
|
||||
<main className="min-h-screen bg-black">
|
||||
<div className="w-1/2 mx-auto">
|
||||
<Head />
|
||||
<p>Loading...</p>
|
||||
</div>
|
||||
</main>
|
||||
)
|
||||
} else if (status === "unauthenticated") {
|
||||
Router.replace("/").catch(() => {
|
||||
console.error("Failed to reroute user!")
|
||||
})
|
||||
return (
|
||||
<></>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default function RootLayout({ children }: LayoutProps) {
|
||||
return (
|
||||
<main className="min-h-screen bg-black">
|
||||
<div className="lg:w-1/2 sm:w-full mx-auto">
|
||||
<Head />
|
||||
<Header />
|
||||
<main className="bg-black h-screen flex flex-col justify-center items-center overflow-y-hidden">
|
||||
<Head />
|
||||
<div className="flicker">
|
||||
{children}
|
||||
</div>
|
||||
<Footer />
|
||||
</main>
|
||||
)
|
||||
}
|
||||
@@ -1,27 +1,103 @@
|
||||
import Link from "next/link"
|
||||
import { Trash } from "grommet-icons"
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import { api } from "@/utils/api";
|
||||
|
||||
// types
|
||||
import type {
|
||||
MedalApiObject,
|
||||
SteamApiObject,
|
||||
MusicApiObject
|
||||
} from '@/utils/types'
|
||||
|
||||
type SocialCardProps = {
|
||||
name: string,
|
||||
id: number,
|
||||
url: string,
|
||||
isAuthenticated: boolean,
|
||||
deleteCallback: () => void
|
||||
platform: "steam" | "music" | "medal"
|
||||
}
|
||||
|
||||
export default function SocialMediaCard(props: SocialCardProps) {
|
||||
function MedalSocialCard() {
|
||||
const { data: medalData, medalFetchStatus } = api.social.getMedalData.useQuery();
|
||||
|
||||
return (
|
||||
<div className="bg-white p-5 w-full text-left">
|
||||
<Link href={props.url} target="_blank">
|
||||
<h1 className="inline font-bold">{props.name}</h1>
|
||||
</Link>
|
||||
|
||||
{ props.isAuthenticated && (
|
||||
<>
|
||||
<Trash onClick={props.deleteCallback} color="black" className="float-right inline hover:cursor-pointer" />
|
||||
<p className="float-right opacity-50 font-bold inline mr-2">ID: {props.id}</p>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<>
|
||||
{
|
||||
medalData?.data.map((v: MedalApiObject,k: number) => {
|
||||
return <div key={k}>
|
||||
<Image
|
||||
src={v.image[0]?.["#text"] ?? "https://storage.thatalex.dev/content/pfp.jpg"}
|
||||
width="50"
|
||||
height="50"
|
||||
alt={`${v.name} Cover Art`}
|
||||
className="inline mr-2"
|
||||
/>
|
||||
<div className="inline-block align-middle">
|
||||
<Link href={v.url} target="_blank">
|
||||
<h1 className="font-bold w-52 truncate hover:underline">{v.name}</h1>
|
||||
</Link>
|
||||
<p className="opacity-75">{v.artist["#text"]}</p>
|
||||
</div>
|
||||
</div>
|
||||
})
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function SteamSocialCard() {
|
||||
const { data: SteamData, steamFetchStatus } = api.social.getSteamData.useQuery();
|
||||
}
|
||||
|
||||
function MusicSocialCard() {
|
||||
const { data: MusicData, musicFetchStatus } = api.social.getMusicData.useQuery();
|
||||
return
|
||||
}
|
||||
|
||||
export default function SocialCard({ platform }: SocialCardProps) {
|
||||
const [content, setContent] = useState<React.JSX.Element | null>(null)
|
||||
|
||||
|
||||
const platformDisplayElements = () => {
|
||||
if (platform === "music") {
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
{
|
||||
socialData?.data.map((v,k) => {
|
||||
return <div key={k}>
|
||||
<Image
|
||||
src={v.image[0]?.["#text"] ?? "https://storage.thatalex.dev/content/pfp.jpg"}
|
||||
width="50"
|
||||
height="50"
|
||||
alt={`${v.name} Cover Art`}
|
||||
className="inline mr-2"
|
||||
/>
|
||||
<div className="inline-block align-middle">
|
||||
<Link href={v.url} target="_blank">
|
||||
<h1 className="font-bold w-52 truncate hover:underline">{v.name}</h1>
|
||||
</Link>
|
||||
<p className="opacity-75">{v.artist["#text"]}</p>
|
||||
</div>
|
||||
</div>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// return (
|
||||
// <div className="bg-white text-black max-w-fit mx-auto p-4">
|
||||
// <h1 className="text-2xl font-bold inline">{displayPlatform}</h1>
|
||||
// </div>
|
||||
// // <div className="bg-white text-black max-w-fit mx-auto p-4">
|
||||
// // <h1 className="text-2xl font-bold inline">Listening To</h1>
|
||||
|
||||
// // {/* link to lastfm */}
|
||||
// // <Link
|
||||
// // href="https://last.fm/user/lulawex"
|
||||
// // target="_blank"
|
||||
// // className="opacity-75 underline font-bold text-sm ml-2 hover:text-zinc-600"
|
||||
// // >
|
||||
// // Powered by Last.fm
|
||||
// // </Link>
|
||||
// // </div>
|
||||
// )
|
||||
}
|
||||
@@ -5,12 +5,15 @@ export default function Footer() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="relative sm:w-1/2 m-auto mt-5 rounded-t-sm bg-zinc-900 p-2 text-white">
|
||||
<div className="relative rounded-t-sm p-2 text-white opacity-50">
|
||||
<p className="text-center">
|
||||
<Link href="mailto:alex@alexavfrantz.com" className="hover:text-gray-500 hover:underline hover:cursor-pointer">
|
||||
alex@alexavfrantz.com
|
||||
</Link>
|
||||
</p>
|
||||
<p className="text-center">
|
||||
The 'PipBoy' is owned by Bethesda, I'm just doing this for fun!
|
||||
</p>
|
||||
<p className="text-center">
|
||||
© Alex Frantz, {date.getFullYear()}
|
||||
</p>
|
||||
|
||||
+16
-22
@@ -1,31 +1,25 @@
|
||||
import {useSession, signIn, signOut} from 'next-auth/react';
|
||||
import HeaderItem from "./HeaderItem";
|
||||
|
||||
export default function Header() {
|
||||
const { status } = useSession()
|
||||
type HeaderProps = {
|
||||
isNotHomePage: boolean
|
||||
}
|
||||
|
||||
export default function Header({
|
||||
isNotHomePage = false
|
||||
}: HeaderProps) {
|
||||
return (
|
||||
<>
|
||||
<div className="text-white max-w-sm mx-auto pt-2 pb-4">
|
||||
<div className="inline-block pb-2">
|
||||
<HeaderItem content="home" linkTo="/" />
|
||||
<HeaderItem content="links" linkTo="/links" />
|
||||
<HeaderItem content="projects" linkTo="/projects" />
|
||||
{ status === "authenticated" &&
|
||||
<HeaderItem
|
||||
content="create"
|
||||
linkTo="/create"
|
||||
/>
|
||||
}
|
||||
<HeaderItem content={status == "unauthenticated" ? "login" : "logout" } onClick={async () => {
|
||||
if (status == "unauthenticated") {
|
||||
await signIn()
|
||||
} else {
|
||||
await signOut()
|
||||
}
|
||||
}} linkTo="" />
|
||||
</div>
|
||||
<hr />
|
||||
<div className="inline-block pb-2 space-x-6 text-center">
|
||||
<HeaderItem content="HOME" linkTo={
|
||||
isNotHomePage ? "/?noAnimation"
|
||||
: "/"
|
||||
} />
|
||||
<HeaderItem content="LINKS" linkTo="/links" />
|
||||
<HeaderItem content="PROJECTS" linkTo="/projects" />
|
||||
<HeaderItem content="ABOUT" linkTo="/about" />
|
||||
</div>
|
||||
<hr className="border-green-500" />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user