Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[POR-44] Create project pages #85

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
6 changes: 3 additions & 3 deletions app/contact/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const metadata: Metadata = {
export default function Page() {
return (
<>
<header className="mx-auto w-full max-w-2xl space-y-2 animate-fade-in-left delay-500 mb-20">
<header className="mx-auto w-full max-w-2xl space-y-2 animate-fade-in-left delay-500 mb-4">
<h1 className="font-clash font-bold text-5xl text-fade-grad">Contact</h1>
<h4 className="font-clash font-medium text-md text-gray-500">Reach out</h4>
<p className="pb-10 text-pretty font-mono text-sm text-foreground leading-5">
Expand All @@ -28,8 +28,8 @@ export default function Page() {
</p>
<hr />
</header>
<Section className="mt-20 animate-fade-in-left delay-700">
<div className="flex flex-col justify-center items-center mt-20">
<Section className="animate-fade-in-left delay-700">
<div className="flex flex-col justify-center items-center">
<div className="flex flex-col items-center align-middle self-center max-w-2xl w-full gap-10">
<div className="flex flex-col w-full gap-4"></div>
<ContactForm />
Expand Down
13 changes: 11 additions & 2 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import Head from '@/components/head';
import localFont from 'next/font/local';
import { CommandMenu } from '@/components/command-menu';
import { Navbar } from '@/components/navbar';
Expand All @@ -9,6 +8,7 @@ import { data } from '@/data/main';
import Script from 'next/script';
import ProgressIndicator from '@/components/progress-indicator';
import { getPosts } from '@/data/blog';
import { getProjects } from '@/data/projects';

export const clashDisplay = localFont({
src: [
Expand Down Expand Up @@ -55,9 +55,17 @@ export default async function RootLayout({ children }: { children: React.ReactNo
};
});
});
const projectsLinks = await getProjects().then((projects) => {
return projects.map((project) => {
return {
url: `/projects/${project.slug}`,
title: project.title,
type: 'projects'
};
});
});
return (
<html lang="en" className="max-w-full overflow-y-scroll overflow-x-hidden no-scrollbar">
<Head title={`${data.name} | ${data.role}`} url={`${process.env.NEXT_PUBLIC_URL}`} />
<body className="antialiased mb-10 lg:mx-auto">
<Script
strategy="afterInteractive"
Expand Down Expand Up @@ -94,6 +102,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo
type: 'internal'
},
...postsLinks,
...projectsLinks,
...data.contact.social.map((socialMediaLink) => ({
url: socialMediaLink.url,
title: socialMediaLink.name,
Expand Down
16 changes: 14 additions & 2 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
import { HomeLayout } from '@/components/pages/home/layout';
import { data } from '@/data/main';
import { getProjects } from '@/data/projects';
import { Metadata } from 'next';

export default function Page() {
return <HomeLayout />;
export const metadata: Metadata = {
title: `${data.name} | ${data.role}`,
description: data.summary,
alternates: {
canonical: 'https://maria-adriana.com/'
}
};

export default async function Page() {
const projects = await getProjects();
return <HomeLayout projects={projects} />;
}
9 changes: 9 additions & 0 deletions app/projects/[slug]/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ReactNode } from 'react';

export default function Layout({ children }: { children: ReactNode }) {
return (
<section className="project-page mx-auto w-full max-w-2xl animate-fade-in-left delay-500">
{children}
</section>
);
}
143 changes: 143 additions & 0 deletions app/projects/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import { getProject, getProjects } from '@/data/projects';
import { notFound } from 'next/navigation';
import { MDXRemote } from 'next-mdx-remote/rsc';
import remarkGfm from 'remark-gfm';
import remarkFrontmatter from 'remark-frontmatter';
import rehypeSlug from 'rehype-slug';
import rehypeAutolinkHeadings from 'rehype-autolink-headings';
import remarkToc from 'remark-toc';
import { mdxComponents } from '@/components/mdx/components';
import { ArrowLeftIcon, ArrowTopRightIcon, GitHubLogoIcon } from '@radix-ui/react-icons';
import Link from 'next/link';
import { data } from '@/data/main';
import rehypePrettyCode from 'rehype-pretty-code';
import { Badge } from '@/components/ui/badge';

export async function generateMetadata(props: {
params: Promise<{
slug: string;
}>;
}) {
const params = await props.params;
const project = await getProject(params.slug);
return {
title: `${data.name} | ${data.role} :: ${project?.title}`,
description: project?.description + ' ' + data.summary,
alternates: {
canonical: `https://maria-adriana.com/projects/${project?.slug}`
}
};
}

export async function generateStaticParams() {
const projects = await getProjects();
return projects.map((project) => ({ slug: project.slug }));
}

export default async function ProjectPage(props: {
params: Promise<{
slug: string;
}>;
}) {
const params = await props.params;

const project = await getProject(params.slug);

if (!project) {
return notFound();
}

const { title, year, content, technologies } = project;

return (
<>
<header>
<Link
href="/projects"
className="flex flex-row gap-2 font-mono text-sm text-gray-500 dark:text-white/60 mb-8 items-center hover:underline hover:text-orange-500 hover:opacity-75 duration-200"
>
<span className="flex border border-gray-300 dark:border-white/20 bg-card rounded-full h-7 w-7 items-center justify-center">
<ArrowLeftIcon className="text-gray-500 dark:text-white/80" />
</span>
Go back
</Link>
<time className="flex flex-row gap-2 items-center text-pretty font-mono text-xs text-foreground text-gray-500 dark:text-gray-300">
YEAR {year}
</time>
<h1 className="font-clash">{title}</h1>
<div className="mt-6 flex flex-wrap gap-1">
{technologies.map(({ label, icon }) => {
return (
<Badge
className="py-1 px-3 gap-2 text-[10px] hover:mix-blend-luminosity cursor-default"
variant="outline"
key={label}
>
{icon}
<span>{label}</span>
</Badge>
);
})}
</div>
<hr className="mt-2" />
</header>
<article className="flex flex-col gap-2 mt-4">
<section className="summary flex gap-1 flex-row-reverse">
<Badge
className="py-1 px-3 gap-2 text-[10px] hover:mix-blend-luminosity cursor-default"
variant="outline"
>
<Link
className="flex flex-row gap-2"
href={data.github + '/' + project.repo}
target="_blank"
>
<GitHubLogoIcon /> Visit repo
</Link>
</Badge>
{project.liveUrl && (
<Badge
className="py-1 px-3 gap-2 text-[10px] hover:mix-blend-luminosity cursor-default"
variant="outline"
>
<Link
className="flex flex-row gap-2"
href={project.liveUrl}
target="_blank"
>
<ArrowTopRightIcon /> Live demo
</Link>
</Badge>
)}
</section>

<div className="content">
<MDXRemote
source={content}
options={{
mdxOptions: {
remarkPlugins: [
remarkGfm,
remarkFrontmatter,
[
remarkToc,
{
tight: true,
maxDepth: 5
}
]
],
rehypePlugins: [
rehypeSlug,
rehypeAutolinkHeadings,
rehypePrettyCode
]
}
}}
components={mdxComponents}
/>
</div>
</article>
</>
);
}
22 changes: 22 additions & 0 deletions app/projects/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import ProjectsList from '@/components/pages/projects';
import { data } from '@/data/main';
import { getProjects } from '@/data/projects';
import { Metadata } from 'next';

export const metadata: Metadata = {
title: `${data.name} | ${data.role} :: Projects`,
description: 'My personal blog, for rambles and so on → ' + data.summary,
alternates: {
canonical: 'https://maria-adriana.com/projects'
}
};

export async function generateStaticParams() {
const projects = await getProjects();
return projects.map((project) => ({ slug: project.slug }));
}

export default async function Page() {
const projects = await getProjects();
return <ProjectsList projects={projects} />;
}
2 changes: 2 additions & 0 deletions components/bg-grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ export function BGGrid({ children }: { children?: React.ReactNode }) {
/>
</div>
<Image
priority={true}
className="fixed -left-10 top-32 scale-150 fade-in-35 duration-1000 opacity-55 z-[-1]"
alt="Decorative image element"
src={'/images/color_grad.webp'}
height="400"
width={200}
/>
<Image
priority={true}
className="fixed -right-10 -top-32 rotate-180 fade-in-35 duration-1000 opacity-15 z-[-1]"
alt="Decorative image element"
src={'/images/color_grad.webp'}
Expand Down
31 changes: 24 additions & 7 deletions components/command-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const CommandMenu = ({ links }: Props) => {

const internalLinks = links.filter((link) => link.type === 'internal');
const blogLinks = links.filter((link) => link.type === 'blog');
const projectsLinks = links.filter((link) => link.type === 'projects');
const socialsLinks = links.filter((link) => link.type === 'social');

useEffect(() => {
Expand All @@ -39,13 +40,15 @@ export const CommandMenu = ({ links }: Props) => {

return (
<>
<p className="hidden md:inline fixed bottom-0 left-0 right-0 border-t border-t-muted p-1 text-center text-sm text-muted-foreground print:hidden">
Press{' '}
<kbd className="pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground opacity-100">
<span className="text-xs">⌘</span>K
</kbd>{' '}
to open the command menu
</p>
<div className="hidden md:inline fixed bottom-0 left-0 right-0 p-1 print:hidden border-t border-t-muted-foreground dark:border-b-[#4D2512] from-white-600/30 dark:from-teal-200/30 via-white dark:via-black to-slate-600/30 dark:to-slate-600/30 backdrop-blur-sm">
<p className="text-center text-sm text-muted-foreground">
Press{' '}
<kbd className="pointer-events-none inline-flex h-5 select-none items-center gap-1 rounded border bg-muted px-1.5 font-mono text-[10px] font-medium text-muted-foreground opacity-100">
<span className="text-xs">⌘</span>K
</kbd>{' '}
to open the command menu
</p>
</div>
<CommandDialog open={open} onOpenChange={setOpen}>
<CommandInput placeholder="Type a command or search..." />
<CommandList>
Expand All @@ -64,6 +67,20 @@ export const CommandMenu = ({ links }: Props) => {
))}
</CommandGroup>
<CommandSeparator />
<CommandGroup heading="Projects">
{projectsLinks.map(({ url, title }) => (
<CommandItem
key={url}
onSelect={() => {
setOpen(false);
window.location.href = url;
}}
>
<span>{title}</span>
</CommandItem>
))}
</CommandGroup>
<CommandSeparator />
<CommandGroup heading="Blog">
{blogLinks.map(({ url, title }) => (
<CommandItem
Expand Down
54 changes: 0 additions & 54 deletions components/head.tsx

This file was deleted.

3 changes: 3 additions & 0 deletions components/navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ const navItems = {
'/': {
name: 'home'
},
'/projects': {
name: 'projects'
},
'/blog': {
name: 'blog'
},
Expand Down
Loading