add blog post, projects
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
import ErrorState from "./ErrorState";
|
||||
import { useState, useEffect } from "react";
|
||||
import type { BlogPost } from "../utils/types";
|
||||
|
||||
export default function BlogRow() {
|
||||
const [post, setPost] = useState<BlogPost | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
fetch("https://blog.alexav.gg/api/posts", {
|
||||
method: "GET",
|
||||
}).then(async (res) => {
|
||||
if (res.ok) {
|
||||
try {
|
||||
const data = await res.json();
|
||||
setPost(data[0]);
|
||||
} catch (e) {
|
||||
console.error("An error occurred fetching blog posts!", e);
|
||||
}
|
||||
} else console.error("Failed to fetch blog posts!");
|
||||
});
|
||||
}, []);
|
||||
|
||||
if (post) {
|
||||
return (
|
||||
<div>
|
||||
<a href="https://blog.alexav.gg">
|
||||
<h1>{post?.title}</h1>
|
||||
<p>{post?.description}</p>
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
} else return <ErrorState label="nothing posted yet :(" />;
|
||||
}
|
||||
@@ -1,31 +1,9 @@
|
||||
export default function ErrorState({
|
||||
type = "error",
|
||||
}: {
|
||||
type: "error" | "loading" | "unavailable";
|
||||
}) {
|
||||
if (type === "error") {
|
||||
return (
|
||||
<div className="flex flex-col bg-black text-white">
|
||||
<div className="px-2 text-center">
|
||||
<p>whoops, something went wrong</p>
|
||||
</div>
|
||||
export default function ErrorState({ label }: { label: string }) {
|
||||
return (
|
||||
<div className="flex flex-col bg-black text-white">
|
||||
<div className="px-2 text-center">
|
||||
<p>{label}</p>
|
||||
</div>
|
||||
);
|
||||
} else if (type === "loading") {
|
||||
return (
|
||||
<div className="flex flex-col bg-black text-white">
|
||||
<div className="px-2 text-center">
|
||||
<h1 className="font-semibold">loading..</h1>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else if (type === "unavailable") {
|
||||
return (
|
||||
<div className="flex flex-col bg-black text-white">
|
||||
<div className="px-2 text-center">
|
||||
<p>no game launched recently</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -34,29 +34,17 @@ export default function GameComponent() {
|
||||
fetchGame();
|
||||
}, []);
|
||||
|
||||
if (game) {
|
||||
return (
|
||||
<a href={`https://medal.tv/u/alexav`} target="_blank">
|
||||
<div className="flex flex-col bg-black border border-black text-white">
|
||||
<div className="flex">
|
||||
<Gamepad className="w-full h-full bg-white text-black" />
|
||||
<div className="pl-2 pr-1">
|
||||
<p className="w-[150px] truncate overflow-hidden whitespace-nowrap">
|
||||
{game.currentlyPlaying.game}
|
||||
</p>
|
||||
<p>
|
||||
{" "}
|
||||
since{" "}
|
||||
{new Date(
|
||||
game.currentlyPlaying.startedPlayingAt,
|
||||
).toLocaleTimeString()}
|
||||
</p>
|
||||
</div>
|
||||
return (
|
||||
<a href="https://medal.tv/u/alexav" target="_blank">
|
||||
<div className="bg-white p-2 rounded-lg w-full min-h-full flex justify-center text-black">
|
||||
<div className="flex justify-center items-center">
|
||||
<div className="px-2">
|
||||
<p className="text-sm font-semibold">
|
||||
{game?.currentlyPlaying.game || "Nothing playing"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
);
|
||||
} else {
|
||||
return <ErrorState type="unavailable" />;
|
||||
}
|
||||
</div>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import type { LastFMMusicObject } from "../../utils/types";
|
||||
import ErrorState from "../ErrorState";
|
||||
|
||||
export default function MusicComponent() {
|
||||
const [music, setMusic] = useState<LastFMMusicObject | null>(null);
|
||||
const [failedFetch, setFailedFetch] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchMusic() {
|
||||
@@ -13,10 +11,9 @@ export default function MusicComponent() {
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
setMusic(data as LastFMMusicObject);
|
||||
} else setFailedFetch(true);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch music!", e);
|
||||
setFailedFetch(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,27 +23,23 @@ export default function MusicComponent() {
|
||||
fetchMusic();
|
||||
}, []);
|
||||
|
||||
if (!failedFetch) {
|
||||
if (music) {
|
||||
return (
|
||||
<a href="https://koito.fntz.net" target="_blank">
|
||||
<div className="w-full bg-black">
|
||||
<div className="text-center">
|
||||
<div className="pl-2 pr-1">
|
||||
<p className="text-lg">
|
||||
<span className="font-semibold">Currently Playing - </span>
|
||||
<span className="underline">{music.title}</span> by{" "}
|
||||
<span className="underline">{music.artist}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
return (
|
||||
<a href="https://koito.fntz.net" target="_blank">
|
||||
<div className="bg-white p-2 rounded-lg w-full min-h-full text-black">
|
||||
<div className="flex justify-center items-center">
|
||||
<img
|
||||
src={
|
||||
music?.images.filter((v) => v.size === "medium")[0]["url"] ||
|
||||
music?.images[0].url
|
||||
}
|
||||
className="border-green-500 border-2"
|
||||
/>
|
||||
<div className="px-2">
|
||||
<p className="text-sm font-semibold">{music?.title}</p>
|
||||
<p className="text-xs">{music?.artist}</p>
|
||||
</div>
|
||||
</a>
|
||||
);
|
||||
} else {
|
||||
return <ErrorState type="loading" />;
|
||||
}
|
||||
} else {
|
||||
return <ErrorState type="error" />;
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -67,9 +67,9 @@ export default function StatModule() {
|
||||
</a>
|
||||
);
|
||||
} else {
|
||||
return <ErrorState type="loading" />;
|
||||
return <ErrorState label="loading.." />;
|
||||
}
|
||||
} else {
|
||||
return <ErrorState type="error" />;
|
||||
return <ErrorState label="something went wrong! :(" />;
|
||||
}
|
||||
}
|
||||
|
||||
+19
-1
@@ -3,6 +3,9 @@ import ProjectCard from "../components/ProjectCard";
|
||||
import FantasyStatus from "../components/FantasyStatus";
|
||||
import PictureCarousel from "../components/modules/PictureCarousel";
|
||||
import Footer from "../components/Footer";
|
||||
import BlogRow from "../components/BlogRow";
|
||||
import GameComponent from "../components/info/GameComponent";
|
||||
import MusicComponent from "../components/info/MusicComponent";
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
@@ -43,6 +46,15 @@ export default function App() {
|
||||
|
||||
<hr className="my-4 border-zinc-800" />
|
||||
|
||||
<p className="opacity-85 text-sm text-left pb-2 underline">
|
||||
<a href="https://blog.alexav.gg" target="_blank">
|
||||
LATEST BLOG POST
|
||||
</a>
|
||||
</p>
|
||||
<BlogRow />
|
||||
|
||||
<hr className="my-4 border-zinc-800" />
|
||||
|
||||
<p className="opacity-85 text-sm text-left pb-2">THINGS I'VE BUILT</p>
|
||||
<div className="my-2 space-y-2">
|
||||
<ProjectCard
|
||||
@@ -81,7 +93,13 @@ export default function App() {
|
||||
|
||||
<hr className="my-4 border-zinc-800" />
|
||||
|
||||
<p className="opacity-85 text-sm text-left pb-2">FUN STUFF</p>
|
||||
<p className="opacity-85 text-sm text-left pb-2">MY ACTIVITIES</p>
|
||||
|
||||
<div className="grid sm:grid-cols-2 grid-cols-1 gap-2">
|
||||
<GameComponent />
|
||||
<MusicComponent />
|
||||
</div>
|
||||
|
||||
<div className="my-2 space-y-6">
|
||||
<div>
|
||||
<h1 className="text-sm opacity-85 font-semibold">Fantasy</h1>
|
||||
|
||||
@@ -93,6 +93,13 @@ type MLBTeam = {
|
||||
score: number;
|
||||
};
|
||||
|
||||
interface BlogPost {
|
||||
id: number;
|
||||
title: string;
|
||||
description: string;
|
||||
slug: string;
|
||||
}
|
||||
|
||||
export type {
|
||||
LastFMMusicObject,
|
||||
LastFMImageObject,
|
||||
@@ -104,4 +111,5 @@ export type {
|
||||
BillsScore,
|
||||
SabresScore,
|
||||
YankeesScore,
|
||||
BlogPost,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user