move projects to projects page
This commit is contained in:
@@ -10,24 +10,26 @@ type ProjectCardProps = {
|
|||||||
|
|
||||||
export default function ProjectCard(props: ProjectCardProps) {
|
export default function ProjectCard(props: ProjectCardProps) {
|
||||||
const technologies = props.technologies.map((v,k) => {
|
const technologies = props.technologies.map((v,k) => {
|
||||||
return <p key={k} className="border-solid border border-red-500 max-w-fit p-1 inline">{v}</p>
|
return <div key={k} className="inline">
|
||||||
|
<div className="max-w-fit p-1 inline">
|
||||||
|
{v}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="lg:w-1/2 sm:max-w-1/2 rounded-lf">
|
<div className="bg-zinc-700 max-w-lg">
|
||||||
<div className="top-0 left-0 p-2 bg-gray-800">
|
<div className="p-2 space-y-2 space-x-2">
|
||||||
<div className="pb-2">
|
<h1 className="font-bold text-2xl inline pl-2">{props.name}</h1>
|
||||||
<p className="font-bold inline pr-2">{props.name}</p>
|
<div className="inline-block">
|
||||||
<div className="pt-2 pb-2 inline-block space-x-2">
|
|
||||||
{technologies}
|
{technologies}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<hr className="max-w-xs" />
|
||||||
<hr />
|
<p>{props.description}</p>
|
||||||
<p className="text-sm pt-2 leading-6">{props.description}</p>
|
|
||||||
|
|
||||||
<div className="block pt-2">
|
<div className="bg-zinc-900 max-w-fit p-2 rounded-lg">
|
||||||
<Link href={props.urlTo} target="_blank">
|
<Link href={props.urlTo} target="_blank">
|
||||||
<p className="bg-zinc-900 max-w-fit p-2 rounded-sm">Source</p>
|
<p>Source</p>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -28,28 +28,19 @@ export default function RootLayout({ children, protectedPage }: LayoutProps) {
|
|||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
)
|
)
|
||||||
}
|
} else if (status === "unauthenticated") {
|
||||||
|
|
||||||
if (status === "unauthenticated") {
|
|
||||||
Router.replace("/").catch(() => {
|
Router.replace("/").catch(() => {
|
||||||
console.error("Failed to reroute user!")
|
console.error("Failed to reroute user!")
|
||||||
})
|
})
|
||||||
} else {
|
|
||||||
return (
|
return (
|
||||||
<main className="min-h-screen bg-black">
|
<></>
|
||||||
<div className="w-1/2 mx-auto">
|
|
||||||
<Head />
|
|
||||||
<Header />
|
|
||||||
{children}
|
|
||||||
<Footer />
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<main className="min-h-screen bg-black">
|
<main className="min-h-screen bg-black">
|
||||||
<div className="w-1/2 mx-auto">
|
<div className="lg:w-1/2 sm:w-full mx-auto">
|
||||||
<Head />
|
<Head />
|
||||||
<Header />
|
<Header />
|
||||||
{children}
|
{children}
|
||||||
@@ -57,5 +48,4 @@ export default function RootLayout({ children, protectedPage }: LayoutProps) {
|
|||||||
<Footer />
|
<Footer />
|
||||||
</main>
|
</main>
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@ export default function Header() {
|
|||||||
<div className="inline-block pb-2">
|
<div className="inline-block pb-2">
|
||||||
<HeaderItem content="home" linkTo="/" />
|
<HeaderItem content="home" linkTo="/" />
|
||||||
<HeaderItem content="links" linkTo="/links" />
|
<HeaderItem content="links" linkTo="/links" />
|
||||||
<HeaderItem content="blog" linkTo="/blog" />
|
<HeaderItem content="projects" linkTo="/projects" />
|
||||||
{ status === "authenticated" &&
|
{ status === "authenticated" &&
|
||||||
<HeaderItem
|
<HeaderItem
|
||||||
content="create"
|
content="create"
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
import RootLayout from '@/components/RootLayout';
|
|
||||||
|
|
||||||
// next modules
|
|
||||||
import Router, {useRouter} from 'next/router';
|
|
||||||
import Link from 'next/link';
|
|
||||||
import Markdown from 'react-markdown';
|
|
||||||
import remarkGfm from 'remark-gfm';
|
|
||||||
import {useSession} from 'next-auth/react';
|
|
||||||
|
|
||||||
// api
|
|
||||||
import {api} from '@/utils/api'
|
|
||||||
|
|
||||||
// icons
|
|
||||||
import { Trash } from 'grommet-icons';
|
|
||||||
|
|
||||||
export default function BlogPage() {
|
|
||||||
const router = useRouter()
|
|
||||||
const id = Number(router.query.id)
|
|
||||||
const { status } = useSession()
|
|
||||||
|
|
||||||
// trpc stuff
|
|
||||||
const {data: blogData} = api.blog.getOne.useQuery(id)
|
|
||||||
const deletionMutation = api.blog.delete.useMutation()
|
|
||||||
|
|
||||||
function deleteItem() {
|
|
||||||
if (blogData) {
|
|
||||||
deletionMutation.mutate(id)
|
|
||||||
Router.replace("/").catch(() => {
|
|
||||||
console.error("Failed to reroute user!")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blogData) {
|
|
||||||
return (
|
|
||||||
<RootLayout>
|
|
||||||
<div className="mx-auto w-1/2 text-white">
|
|
||||||
<h1 className="text-2xl font-bold text-center">{blogData.name} { status == "authenticated" ? <Trash onClick={deleteItem} className="hover:cursor-pointer" /> : ""}</h1>
|
|
||||||
|
|
||||||
<div className="pt-2 pb-2">
|
|
||||||
<hr />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Markdown remarkPlugins={[remarkGfm]} className="text-white w-1/2 mx-auto">
|
|
||||||
{blogData.contents}
|
|
||||||
</Markdown>
|
|
||||||
</div>
|
|
||||||
</RootLayout>
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<RootLayout>
|
|
||||||
<div className="text-center text-2xl font-bold text-white">
|
|
||||||
<p>Well, that's not good..</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="text-center text-white">
|
|
||||||
<p>You've reached a page that doesn't exist. Lets fix that.</p>
|
|
||||||
<Link href="/" className="hover:underline hover:cursor-pointer hover:text-gray-500">
|
|
||||||
Head Home
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</RootLayout>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
// trpc api
|
|
||||||
import { api } from "@/utils/api";
|
|
||||||
import {useState, useRef} from 'react';
|
|
||||||
import Markdown from 'react-markdown'
|
|
||||||
import remarkGfm from 'remark-gfm'
|
|
||||||
|
|
||||||
// components
|
|
||||||
import RootLayout from '@/components/RootLayout';
|
|
||||||
|
|
||||||
// types
|
|
||||||
import type { FormEvent } from "react";
|
|
||||||
|
|
||||||
export default function BlogCreatePage() {
|
|
||||||
const [textContent, setTextContent] = useState<string | null>(null)
|
|
||||||
const [showMarkdown, setShowMarkdown] = useState<boolean>(false)
|
|
||||||
|
|
||||||
// element refs
|
|
||||||
const titleRef = useRef<HTMLInputElement>(null)
|
|
||||||
const tagRef = useRef<HTMLInputElement>(null)
|
|
||||||
const imageRef = useRef<HTMLInputElement>(null)
|
|
||||||
|
|
||||||
// trpc mutation
|
|
||||||
const blogPostMutation = api.blog.create.useMutation()
|
|
||||||
|
|
||||||
function handleElementUpdate(e: FormEvent) {
|
|
||||||
const textarea = e.target as HTMLTextAreaElement
|
|
||||||
setTextContent(textarea.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
function submitBlogPost() {
|
|
||||||
if (!textContent || textContent == "") {
|
|
||||||
console.error("No text provided")
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!titleRef || !tagRef || !titleRef.current?.value || !tagRef.current?.value || titleRef.current?.value == "" || tagRef.current?.value == "") {
|
|
||||||
console.error("No title/tagline provided")
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!imageRef?.current?.value || imageRef.current?.value == "") {
|
|
||||||
console.error("No image URL provided")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
name: titleRef.current?.value,
|
|
||||||
tagline: tagRef.current?.value,
|
|
||||||
image: imageRef.current?.value,
|
|
||||||
contents: textContent,
|
|
||||||
}
|
|
||||||
|
|
||||||
blogPostMutation.mutate(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<RootLayout protectedPage={true}>
|
|
||||||
<div className="text-center pb-2">
|
|
||||||
<button className="text-white mx-auto" onClick={() => setShowMarkdown(!showMarkdown)}>Show {showMarkdown ? "Text" : "Markdown"}</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{
|
|
||||||
showMarkdown ? <Markdown remarkPlugins={[remarkGfm]} className="text-white w-1/2 mx-auto">
|
|
||||||
{textContent}
|
|
||||||
</Markdown>
|
|
||||||
: <textarea onInput={handleElementUpdate} className="resize-none block h-96 w-1/2 mx-auto bg-gray-900 rounded-sm text-white" defaultValue={textContent ?? ""} />
|
|
||||||
}
|
|
||||||
|
|
||||||
<div className="text-center pt-4 space-y-2">
|
|
||||||
<input type="text" ref={titleRef} placeholder="title" name="title" /><br />
|
|
||||||
<input type="text" ref={imageRef} placeholder="image url" name="image" /><br />
|
|
||||||
<input type="text" ref={tagRef} placeholder="tagline" name="tag" /><br />
|
|
||||||
|
|
||||||
<button onClick={submitBlogPost} className="text-white">Submit</button>
|
|
||||||
</div>
|
|
||||||
</RootLayout>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
import RootLayout from "@/components/RootLayout"
|
|
||||||
import BlogCard from "@/components/BlogCard"
|
|
||||||
import NotFound from "@/components/NotFound";
|
|
||||||
import React, {useState, useEffect} from 'react';
|
|
||||||
import { api } from "@/utils/api";
|
|
||||||
|
|
||||||
type GenericItemType = {
|
|
||||||
name: string,
|
|
||||||
image: string,
|
|
||||||
tagline: string,
|
|
||||||
id: number
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Blog() {
|
|
||||||
const {data: itemData, isLoading: areItemsLoading} = api.blog.getAll.useQuery()
|
|
||||||
const [list, setList] = useState<null | JSX.Element[]>(null)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (itemData) {
|
|
||||||
setList(
|
|
||||||
itemData.map((v: GenericItemType, k) => {
|
|
||||||
return <BlogCard
|
|
||||||
name={v.name}
|
|
||||||
tagline={v.tagline}
|
|
||||||
id={v.id}
|
|
||||||
image={v.image}
|
|
||||||
key={k}
|
|
||||||
/>
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}, [itemData])
|
|
||||||
|
|
||||||
if (list) {
|
|
||||||
return (
|
|
||||||
<RootLayout>
|
|
||||||
<div className="text-white w-1/2 mx-auto">
|
|
||||||
<div className="space-x-2 space-y-2">
|
|
||||||
{
|
|
||||||
list.length > 0 ? list : <NotFound />
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</RootLayout>
|
|
||||||
)
|
|
||||||
} else if (areItemsLoading) {
|
|
||||||
<RootLayout>
|
|
||||||
<div className="text-white">
|
|
||||||
<p>Loading..</p>
|
|
||||||
</div>
|
|
||||||
</RootLayout>
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<RootLayout>
|
|
||||||
<NotFound />
|
|
||||||
</RootLayout>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
-39
@@ -1,6 +1,5 @@
|
|||||||
import RootLayout from "@/components/RootLayout";
|
import RootLayout from "@/components/RootLayout";
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import ProjectCard from "@/components/ProjectsCard";
|
|
||||||
import { Cli } from "grommet-icons";
|
import { Cli } from "grommet-icons";
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
@@ -15,7 +14,7 @@ export default function Home() {
|
|||||||
<hr className="h-px my-2 bg-gray-200 border-0 w-1/2 mx-auto dark:bg-gray-700" />
|
<hr className="h-px my-2 bg-gray-200 border-0 w-1/2 mx-auto dark:bg-gray-700" />
|
||||||
|
|
||||||
<div className="my-4">
|
<div className="my-4">
|
||||||
<div className="bg-terminalback lg:max-w-xl sm:max-w-full m-auto">
|
<div className="bg-terminalback lg:max-w-xl md:max-w-xl sm:max-w-full m-auto">
|
||||||
<div className="bg-terminalbar">
|
<div className="bg-terminalbar">
|
||||||
<div className="pt-2 pl-2">
|
<div className="pt-2 pl-2">
|
||||||
<div className="bg-terminalback w-60 rounded-t-md">
|
<div className="bg-terminalback w-60 rounded-t-md">
|
||||||
@@ -52,43 +51,6 @@ export default function Home() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr className="h-px my-2 bg-gray-200 border-0 w-1/2 mx-auto dark:bg-gray-700" />
|
<hr className="h-px my-2 bg-gray-200 border-0 w-1/2 mx-auto dark:bg-gray-700" />
|
||||||
|
|
||||||
<div>
|
|
||||||
<h1 className="text-center text-2xl font-bold">Projects</h1>
|
|
||||||
<div className="mt-2 flex flex-col justify-center items-center space-y-2">
|
|
||||||
<ProjectCard
|
|
||||||
name="SplitStat"
|
|
||||||
description="SplitStat was a Discord bot that allowed you to see your stats & other player stats from the Splitgate game. It would also allow you to see the results of an in-game match or what matches a player had played recently."
|
|
||||||
urlTo="https://github.com/azpha/splitstat"
|
|
||||||
technologies={
|
|
||||||
[
|
|
||||||
"JavaScript",
|
|
||||||
"Server Management"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<ProjectCard
|
|
||||||
name="Rconify"
|
|
||||||
description="Rconify is a JavaScript package that allows you to connect & issue commands to a Valve-compliant RCON game server. This is useful for firing commands to games like Minecraft, Project Zomboid and more."
|
|
||||||
urlTo="https://github.com/azpha/rconify"
|
|
||||||
technologies={
|
|
||||||
[
|
|
||||||
"TypeScript",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<ProjectCard
|
|
||||||
name="MCSRVSTAT Wrapper"
|
|
||||||
description="MCSRVSTAT is a Minecraft server status website that provides an API to check the status/retrieve information about a Minecraft server. This package is a wrapper of that API, easily allowing you to fetch data from your NodeJS code."
|
|
||||||
urlTo="https://github.com/azpha/mcsrvstat-js"
|
|
||||||
technologies={
|
|
||||||
[
|
|
||||||
"JavaScript",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</RootLayout>
|
</RootLayout>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
import ProjectCard from "@/components/ProjectsCard"
|
||||||
|
import RootLayout from "@/components/RootLayout"
|
||||||
|
|
||||||
|
export default function Projects() {
|
||||||
|
return (
|
||||||
|
<RootLayout>
|
||||||
|
<div className="text-white">
|
||||||
|
<div className="mb-4">
|
||||||
|
<h1 className="font-bold text-2xl text-center">Projects</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-2 w-full flex flex-col justify-center items-center">
|
||||||
|
<ProjectCard
|
||||||
|
name="SplitStat"
|
||||||
|
description="SplitStat was a Discord bot that allowed you to see your stats & other player stats from the Splitgate game. It would also allow you to see the results of an in-game match or what matches a player had played recently."
|
||||||
|
urlTo="https://github.com/azpha/splitstat"
|
||||||
|
technologies={
|
||||||
|
[
|
||||||
|
"JavaScript",
|
||||||
|
"Linux"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ProjectCard
|
||||||
|
name="SplitStat"
|
||||||
|
description="SplitStat was a Discord bot that allowed you to see your stats & other player stats from the Splitgate game. It would also allow you to see the results of an in-game match or what matches a player had played recently."
|
||||||
|
urlTo="https://github.com/azpha/splitstat"
|
||||||
|
technologies={
|
||||||
|
[
|
||||||
|
"JavaScript",
|
||||||
|
"Linux"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ProjectCard
|
||||||
|
name="SplitStat"
|
||||||
|
description="SplitStat was a Discord bot that allowed you to see your stats & other player stats from the Splitgate game. It would also allow you to see the results of an in-game match or what matches a player had played recently."
|
||||||
|
urlTo="https://github.com/azpha/splitstat"
|
||||||
|
technologies={
|
||||||
|
[
|
||||||
|
"JavaScript",
|
||||||
|
"Linux"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ProjectCard
|
||||||
|
name="SplitStat"
|
||||||
|
description="SplitStat was a Discord bot that allowed you to see your stats & other player stats from the Splitgate game. It would also allow you to see the results of an in-game match or what matches a player had played recently."
|
||||||
|
urlTo="https://github.com/azpha/splitstat"
|
||||||
|
technologies={
|
||||||
|
[
|
||||||
|
"JavaScript",
|
||||||
|
"Linux"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ProjectCard
|
||||||
|
name="SplitStat"
|
||||||
|
description="SplitStat was a Discord bot that allowed you to see your stats & other player stats from the Splitgate game. It would also allow you to see the results of an in-game match or what matches a player had played recently."
|
||||||
|
urlTo="https://github.com/azpha/splitstat"
|
||||||
|
technologies={
|
||||||
|
[
|
||||||
|
"JavaScript",
|
||||||
|
"Linux"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ProjectCard
|
||||||
|
name="SplitStat"
|
||||||
|
description="SplitStat was a Discord bot that allowed you to see your stats & other player stats from the Splitgate game. It would also allow you to see the results of an in-game match or what matches a player had played recently."
|
||||||
|
urlTo="https://github.com/azpha/splitstat"
|
||||||
|
technologies={
|
||||||
|
[
|
||||||
|
"JavaScript",
|
||||||
|
"Linux"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</RootLayout>
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user