-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
46 changed files
with
2,662 additions
and
71 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
npx --no-install commitlint --edit "$1" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
npx lint-staged |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"**/*.{js,jsx,ts,tsx}": ["eslint --max-warnings=0", "prettier --write"], | ||
"**/*.{html,json,css,scss,md,mdx}": ["prettier -w"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { AdminBlogFormState, AdminBlogSchema } from '@/zod_schemas/admin'; | ||
|
||
export default async function adminBlogSubmit(state: AdminBlogFormState, formData: FormData) { | ||
const validatedFields = AdminBlogSchema.safeParse({ | ||
id: formData.get('id') ? Number(formData.get('id')) : undefined, | ||
title: formData.get('title'), | ||
tag: formData.get('tag'), | ||
content: formData.get('content'), | ||
}); | ||
|
||
if (!validatedFields.success) { | ||
console.log(validatedFields.error); | ||
return { | ||
errors: validatedFields.error.flatten().fieldErrors, | ||
}; | ||
} | ||
|
||
try { | ||
const res = await fetch('/api/blog', { | ||
method: 'PATCH', | ||
body: JSON.stringify(validatedFields.data), | ||
headers: { | ||
'Content-Type': 'application/json', | ||
}, | ||
}); | ||
|
||
if (!res.ok) { | ||
const err = await res.json(); | ||
return { message: err }; | ||
} | ||
|
||
const data = await res.json(); | ||
return { message: data }; | ||
} catch (err) { | ||
console.error(err); | ||
return { message: 'API call failed' }; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import AdminBlogForm from '@/components/admin/forms/BlogForm'; | ||
import { db } from '@/db'; | ||
import { posts, PostSelect } from '@/db/schema'; | ||
import { eq } from 'drizzle-orm'; | ||
|
||
export default async function Page({ params }: { params: { slug: string } }) { | ||
const postData: PostSelect = ( | ||
await db.select().from(posts).where(eq(posts.slug, params.slug)) | ||
)[0]; | ||
|
||
return ( | ||
<AdminBlogForm | ||
id={postData.id} | ||
title={postData.title} | ||
tag={postData.tag} | ||
content={postData.content} | ||
cover={postData.cover} | ||
/> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import AdminBlogForm from "@/components/admin/forms/BlogForm"; | ||
|
||
export default function AdminNewBlogPage() { | ||
return <AdminBlogForm />; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { db } from '@/db'; | ||
import { posts, PostSelect } from '@/db/schema'; | ||
import { | ||
Table, | ||
TableBody, | ||
TableCell, | ||
TableHead, | ||
TableHeader, | ||
TableRow, | ||
} from '@/components/ui/table'; | ||
import { Button } from '@/components/ui/button'; | ||
import Link from 'next/link'; | ||
import { Badge } from '@/components/ui/badge'; | ||
import AdminBlogDeleteButton from '@/app/_components/_admin/BlogDeleteButton'; | ||
|
||
export default async function AdminBlogPage() { | ||
const postsData: Omit<PostSelect, 'content' | 'cover' | 'createdAt'>[] = await db | ||
.select({ | ||
id: posts.id, | ||
title: posts.title, | ||
slug: posts.slug, | ||
tag: posts.tag, | ||
}) | ||
.from(posts); | ||
|
||
return ( | ||
<> | ||
<div className="flex items-center justify-between"> | ||
<h2 className="text-3xl font-bold"> | ||
Admin Blog | ||
<span className="text-primary">.</span> | ||
</h2> | ||
<Button asChild> | ||
<Link href="/admin/blog/new">New Post</Link> | ||
</Button> | ||
</div> | ||
<Table> | ||
<TableHeader> | ||
<TableRow> | ||
<TableHead>Id</TableHead> | ||
<TableHead>Title</TableHead> | ||
<TableHead>Tag</TableHead> | ||
<TableHead></TableHead> | ||
</TableRow> | ||
</TableHeader> | ||
<TableBody> | ||
{postsData.map((post) => ( | ||
<TableRow> | ||
<TableCell>{post.id}</TableCell> | ||
<TableCell className="font-medium"> | ||
<Link href={`/blog/${post.slug}`} className="underline"> | ||
{post.title} | ||
</Link> | ||
</TableCell> | ||
<TableCell> | ||
<Badge className="capitalize" variant="secondary"> | ||
{post.tag} | ||
</Badge> | ||
</TableCell> | ||
<TableCell className="flex gap-4"> | ||
<Button size="sm"> | ||
<Link href={`/admin/blog/${post.slug}`}>Edit</Link> | ||
</Button> | ||
<AdminBlogDeleteButton postId={post.id} /> | ||
</TableCell> | ||
</TableRow> | ||
))} | ||
</TableBody> | ||
</Table> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { redirect } from "next/navigation"; | ||
|
||
export default async function AdminPage() { | ||
redirect('/admin/blog'); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import AdminBar from "@/components/admin/AdminBar"; | ||
|
||
export default function ProtectedLayout({ | ||
children, | ||
}: Readonly<{ | ||
children: React.ReactNode; | ||
}>) { | ||
return ( | ||
<main className="mb-40 mt-10 flex w-full flex-col gap-10 md:mb-10"> | ||
<AdminBar /> | ||
{children} | ||
</main> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
import React from 'react'; | ||
|
||
export default function WritingsLayout({ children }: Readonly<{ children: React.ReactNode }>) { | ||
export default function BlogLayout({ children }: Readonly<{ children: React.ReactNode }>) { | ||
return <main className="mb-40 mt-10 flex w-full flex-col gap-10 md:mb-10">{children}</main>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import AppBar from "@/components/main/AppBar"; | ||
|
||
export default function MainLayout({ | ||
children, | ||
}: Readonly<{ | ||
children: React.ReactNode; | ||
}>) { | ||
return ( | ||
<> | ||
{children} | ||
<AppBar /> | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import MoonlitGraceArt from '@/components/main/MoonlitGraceArt'; | ||
import { Metadata } from 'next'; | ||
|
||
export const metadata: Metadata = { | ||
title: 'Moonlitgrace', | ||
description: | ||
'Step into Moonlitgrace, where a passionate web developer and open-source contributor shares insights, projects, and creativity—all under the alias Moonlitgrace.', | ||
}; | ||
|
||
export default function Home() { | ||
return ( | ||
<main className="grid w-full place-items-center"> | ||
<MoonlitGraceArt /> | ||
</main> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
'use client'; | ||
|
||
import { Button } from '@/components/ui/button'; | ||
import { useState } from 'react'; | ||
|
||
export default function AdminBlogDeleteButton({ postId }: { postId: number }) { | ||
const [pending, setPending] = useState(false); | ||
|
||
async function handleDeleteBlog() { | ||
setPending(true); | ||
try { | ||
const result = confirm(`Sure to delete blog: ${postId}?`); | ||
if (result) { | ||
await fetch('/api/blog/', { | ||
method: 'DELETE', | ||
body: JSON.stringify({ postId }), | ||
headers: { | ||
'Content-Type': 'application/json', | ||
}, | ||
}); | ||
} | ||
} catch (err) { | ||
console.error(err); | ||
} finally { | ||
setPending(false); | ||
} | ||
} | ||
|
||
return ( | ||
<Button disabled={pending} variant="destructive" size="sm" onClick={handleDeleteBlog}> | ||
Delete | ||
</Button> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { db } from '@/db'; | ||
import { posts } from '@/db/schema'; | ||
import { count } from 'drizzle-orm'; | ||
import { NextResponse } from 'next/server'; | ||
|
||
export async function GET() { | ||
try { | ||
const postsCount = (await db.select({ count: count() }).from(posts))[0]; | ||
|
||
const obj = { | ||
posts: postsCount, | ||
}; | ||
|
||
return NextResponse.json(obj); | ||
} catch (err) { | ||
console.log(err); | ||
return NextResponse.json({ message: 'Data counting failed!' }, { status: 500 }); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { db } from '@/db'; | ||
import { posts } from '@/db/schema'; | ||
import { AdminBlogData } from '@/zod_schemas/admin'; | ||
import { eq } from 'drizzle-orm'; | ||
import { NextRequest, NextResponse } from 'next/server'; | ||
import slugify from 'slugify'; | ||
|
||
export async function PATCH(request: NextRequest) { | ||
const data: AdminBlogData = await request.json(); | ||
const isToUpdate = data.id !== undefined; | ||
|
||
try { | ||
if (isToUpdate) { | ||
await db | ||
.update(posts) | ||
.set({ | ||
title: data.title, | ||
tag: data.tag, | ||
content: data.content, | ||
slug: slugify(data.title.toLowerCase()), | ||
...(data.cover && { cover: data.cover }), | ||
}) | ||
.where(eq(posts.id, data.id as number)); | ||
|
||
return NextResponse.json({ message: 'Success' }); | ||
} else { | ||
await db.insert(posts).values({ | ||
title: data.title, | ||
tag: data.tag, | ||
content: data.content, | ||
slug: slugify(data.title.toLowerCase()), | ||
...(data.cover && { cover: data.cover }), | ||
}); | ||
|
||
return NextResponse.json({ message: 'Success' }); | ||
} | ||
} catch (err) { | ||
console.error(err); | ||
return NextResponse.json({ message: 'Data update failed' }, { status: 500 }); | ||
} | ||
} | ||
|
||
export async function DELETE(request: NextRequest) { | ||
const data: { postId: string } = await request.json(); | ||
|
||
try { | ||
await db.delete(posts).where(eq(posts.id, Number(data.postId))); | ||
return NextResponse.json({ message: 'Deleted successfully!' }); | ||
} catch (err) { | ||
console.error(err); | ||
return NextResponse.json({ message: 'Deletion failed!' }, { status: 500 }); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.