Skip to content

Commit 60aeee9

Browse files
committed
Add new article layout and organize article pages
Introduced a new layout component for articles and reorganized article-related pages for better structure. This includes adding pages for authors, categories, tags, and individual author/tag views, and moving some pages for consistency. Took 25 seconds
1 parent 694204a commit 60aeee9

File tree

8 files changed

+237
-2
lines changed

8 files changed

+237
-2
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { prisma } from "@/lib/prisma"
2+
import { notFound } from "next/navigation"
3+
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
4+
import ArticleSearchAndGrid from "@/components/article/ArticleSearchAndGrid"
5+
6+
export async function generateMetadata({ params }: { params: { username: string } }) {
7+
const author = await prisma.user.findUnique({
8+
where: { username: params.username }
9+
})
10+
11+
if (!author) {
12+
return {
13+
title: 'Author Not Found'
14+
}
15+
}
16+
17+
return {
18+
title: `Articles by ${author.name}`,
19+
description: `Browse all articles written by ${author.name}`
20+
}
21+
}
22+
23+
export default async function AuthorPage({ params }: { params: { username: string } }) {
24+
const author = await prisma.user.findUnique({
25+
where: { username: params.username },
26+
include: {
27+
_count: {
28+
select: { authoredArticles: true }
29+
}
30+
}
31+
})
32+
33+
if (!author) {
34+
notFound()
35+
}
36+
37+
return (
38+
<div className="container py-8">
39+
<div className="flex items-center gap-4 mb-8">
40+
<Avatar className="h-20 w-20">
41+
<AvatarImage src={author.image || ''} alt={author.name || ''} />
42+
<AvatarFallback>{author.name?.charAt(0) || 'U'}</AvatarFallback>
43+
</Avatar>
44+
<div>
45+
<h1 className="text-3xl font-bold">{author.name}</h1>
46+
<p className="text-muted-foreground">@{author.username}</p>
47+
{author.bio && <p className="mt-2">{author.bio}</p>}
48+
<p className="text-sm text-muted-foreground mt-1">
49+
{author._count.authoredArticles} articles published
50+
</p>
51+
</div>
52+
</div>
53+
<ArticleSearchAndGrid authorUsername={params.username} />
54+
</div>
55+
)
56+
}

app/articles/authors/page.tsx

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { prisma } from "@/lib/prisma"
2+
import AuthorsList from "@/components/authors/AuthorsList"
3+
4+
export const metadata = {
5+
title: 'Article Authors',
6+
description: 'Browse all article authors'
7+
}
8+
9+
async function getAuthors() {
10+
const authors = await prisma.user.findMany({
11+
where: {
12+
authoredArticles: {
13+
some: {}
14+
}
15+
},
16+
include: {
17+
_count: {
18+
select: { authoredArticles: true }
19+
}
20+
},
21+
orderBy: {
22+
name: 'asc'
23+
}
24+
})
25+
return authors
26+
}
27+
28+
export default async function AuthorsPage() {
29+
const authors = await getAuthors()
30+
31+
return (
32+
<div className="container py-8">
33+
<div className="max-w-4xl mx-auto">
34+
<h1 className="text-3xl font-bold mb-8">Browse Authors</h1>
35+
<AuthorsList authors={authors} />
36+
</div>
37+
</div>
38+
)
39+
}

app/articles/categories/page.tsx

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { prisma } from "@/lib/prisma";
2+
import CategoriesList from "@/components/categories/CategoriesList";
3+
4+
export const metadata = {
5+
title: "Article Categories",
6+
description: "Browse all article categories",
7+
}
8+
9+
async function getCategories() {
10+
return prisma.articleCategory.findMany({
11+
include: {
12+
_count: {
13+
select: {articles: true},
14+
},
15+
},
16+
orderBy: {
17+
name: "asc",
18+
},
19+
});
20+
}
21+
22+
export default async function CategoriesPage() {
23+
const categories = await getCategories()
24+
25+
return (
26+
<div className="container py-8">
27+
<div className="mx-auto max-w-4xl">
28+
<h1 className="mb-8 text-3xl font-bold">Browse Categories</h1>
29+
<CategoriesList categories={categories} />
30+
</div>
31+
</div>
32+
)
33+
}

app/articles/layout.tsx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import React from "react"
2+
3+
import { generalSidebarNav } from "@/config/links"
4+
import { getCurrentUser } from "@/lib/session"
5+
import Footer from "@/components/layout/footer"
6+
import TopNavbar from "@/components/layout/topNavbar"
7+
import { SidebarNav } from "@/components/sidebar-nav"
8+
9+
interface DashboardLayoutProps {
10+
children: React.ReactNode
11+
}
12+
13+
export default async function DashboardLayout({
14+
children,
15+
}: DashboardLayoutProps) {
16+
const user = await getCurrentUser()
17+
18+
return (
19+
<div className="flex min-h-screen flex-col space-y-6">
20+
<TopNavbar
21+
user={{
22+
name: user?.name,
23+
image: user?.image,
24+
email: user?.email,
25+
}}
26+
/>
27+
<div className="container grid flex-1 gap-12 md:grid-cols-[200px_1fr]">
28+
<aside className="hidden w-[200px] flex-col md:flex">
29+
<SidebarNav items={generalSidebarNav.data} />
30+
</aside>
31+
<main
32+
className="flex w-full flex-1 flex-col"
33+
style={{ maxWidth: "90%" }}
34+
>
35+
{children}
36+
</main>
37+
</div>
38+
<Footer />
39+
</div>
40+
)
41+
}

app/researcher/articles/page.tsx renamed to app/articles/page.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
'use client'
2-
31
import ArticleSearchAndGrid from "@/components/article/ArticleSearchAndGrid";
42

53
export default function ArticleList() {
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { prisma } from "@/lib/prisma"
2+
import { notFound } from "next/navigation"
3+
import ArticleSearchAndGrid from "@/components/article/ArticleSearchAndGrid"
4+
5+
export async function generateMetadata({ params }: { params: { tagSlug: string } }) {
6+
const tag = await prisma.articleTag.findUnique({
7+
where: { slug: params.tagSlug }
8+
})
9+
10+
if (!tag) {
11+
return {
12+
title: 'Tag Not Found'
13+
}
14+
}
15+
16+
return {
17+
title: `Articles tagged with ${tag.name}`,
18+
description: `Browse all articles tagged with ${tag.name}`
19+
}
20+
}
21+
22+
export default async function TagPage({ params }: { params: { tagSlug: string } }) {
23+
const tag = await prisma.articleTag.findUnique({
24+
where: { slug: params.tagSlug }
25+
})
26+
27+
if (!tag) {
28+
notFound()
29+
}
30+
31+
return (
32+
<div className="container py-8">
33+
<h1 className="text-3xl font-bold mb-8">Articles tagged with &quot;{tag.name}&quot;</h1>
34+
<ArticleSearchAndGrid tagSlug={params.tagSlug} />
35+
</div>
36+
)
37+
}

app/articles/tags/page.tsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { prisma } from "@/lib/prisma";
2+
import TagsList from "@/components/tags/TagsList";
3+
4+
export const metadata = {
5+
title: "Article Tags",
6+
description: "Browse all article tags",
7+
}
8+
9+
async function getTags() {
10+
return prisma.articleTag.findMany({
11+
include: {
12+
_count: {
13+
select: {articles: true},
14+
},
15+
},
16+
orderBy: {
17+
name: "asc",
18+
},
19+
});
20+
}
21+
export default async function TagsPage() {
22+
const tags = await getTags();
23+
return (
24+
<div className="container py-8">
25+
<div className="mx-auto max-w-4xl">
26+
<h1 className="mb-8 text-3xl font-bold">Browse Tags</h1>
27+
<TagsList tags={tags} />
28+
</div>
29+
</div>
30+
)
31+
}

0 commit comments

Comments
 (0)