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