117 lines
5.0 KiB
TypeScript
117 lines
5.0 KiB
TypeScript
'use client'
|
|
|
|
import { trpc } from "~/app/_trpc/Client";
|
|
import * as Card from "~/components/ui/card";
|
|
import { Badge } from "~/components/ui/badge";
|
|
import { StackBadge } from "~/components/StackBadge";
|
|
import Markdown from "react-markdown";
|
|
import { ScrollArea } from "~/components/ui/scroll-area";
|
|
import AnimatedPageTitle from "../_components/Animated/AnimatedPageTitle";
|
|
import AnimateTextIn from "../_components/Animated/AnimateIn";
|
|
import { useTimeLine } from "../_providers/GsapProvicer";
|
|
import AnimatePopUp from "../_components/Animated/AnimatePopUp";
|
|
import { Button } from "~/components/ui/button";
|
|
import remarkGfm from "remark-gfm"
|
|
|
|
export default function ProjectsPage() {
|
|
const { data: projects, isLoading } = trpc.projectv2.listWithStack.useQuery();
|
|
useTimeLine(projects)
|
|
if (isLoading) {
|
|
return (
|
|
<div className="flex justify-center items-center min-h-[200px] text-muted-foreground">
|
|
Loading...
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (!projects?.length) {
|
|
return (
|
|
<div className="flex justify-center items-center min-h-[200px] text-muted-foreground">
|
|
No projects yet.
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<ScrollArea className="px-10 lg:px-0 w-full h-full max-w-4xl mx-auto pt-10">
|
|
<AnimatedPageTitle position={0}><span>Project I've Been</span><span> Working on</span> </AnimatedPageTitle>
|
|
<div className="pt-10" />
|
|
{projects.map((project, i) => (
|
|
<div id={project.id} key={i} className="scroll-mt-10">
|
|
<Card.AnimatedCard position={i + 1.2} key={project.id}>
|
|
<Card.CardHeader>
|
|
<div className="flex items-start justify-between gap-2 flex-wrap">
|
|
<AnimateTextIn position={i + 1.4} animation="slide"><Card.CardTitle>{project.title}</Card.CardTitle></AnimateTextIn>
|
|
<div className="flex gap-2 flex-wrap">
|
|
{project.sourceType && (
|
|
<AnimatePopUp position={i + 2} duration={2}>
|
|
<Badge variant={project.sourceType === "open" ? "secondary" : "outline"}>
|
|
{project.sourceType === "open" ? "Open Source" : "Closed Source"}
|
|
</Badge>
|
|
</AnimatePopUp>
|
|
)}
|
|
{project.releaseStatus && (
|
|
<Badge variant={project.releaseStatus === "released" ? "default" : "outline"}>
|
|
{project.releaseStatus === "released" ? "Released" : "Unreleased"}
|
|
</Badge>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</Card.CardHeader>
|
|
{(project.description || project.sourceLink || project.releaseLink || project.techStack?.stackItems?.length) && (
|
|
<Card.CardContent className="flex flex-col gap-3">
|
|
{project.description && (
|
|
<div className="prose prose-sm dark:prose-invert max-w-none text-muted-foreground">
|
|
<AnimatePopUp position={i + 1.4} duration={10}>
|
|
<Markdown remarkPlugins={[remarkGfm]}>{project.description}</Markdown>
|
|
</AnimatePopUp>
|
|
</div>
|
|
)}
|
|
<div className="flex flex-row">
|
|
{project.techStack?.stackItems && project.techStack.stackItems.length > 0 && (
|
|
<div className="flex flex-wrap gap-1.5">
|
|
{project.techStack.stackItems.map((item, k) => (
|
|
<AnimatePopUp key={k} position={(i + 2) + k * 0.5}> <StackBadge key={item} item={item} /> </AnimatePopUp>
|
|
))}
|
|
</div>
|
|
)}
|
|
{(project.sourceLink || project.releaseLink) && (
|
|
<div className="ml-auto flex-col lg:flex-row justify-center gap-5">
|
|
{project.sourceLink &&
|
|
<Button variant='outline' className="cursor-pointer mb-3 lg:mb-0 lg:mr-3 min-w-18">
|
|
<a
|
|
href={project.sourceLink}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className='items-center'
|
|
>
|
|
Source
|
|
</a>
|
|
</Button>
|
|
}
|
|
{project.releaseLink &&
|
|
<Button variant='default' className="cursor-pointer min-w-18 items-center">
|
|
<a
|
|
href={project.releaseLink}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className='items-center'
|
|
>
|
|
Live
|
|
</a>
|
|
</Button>
|
|
|
|
}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</Card.CardContent>
|
|
)}
|
|
</Card.AnimatedCard>
|
|
<div className="pt-5" />
|
|
</div>
|
|
))}
|
|
</ScrollArea>
|
|
);
|
|
}
|