From b196249f25dac3dcbac48c7d4d1e325b50eca2f2 Mon Sep 17 00:00:00 2001 From: Jake Jarvis Date: Wed, 14 May 2025 09:47:51 -0400 Subject: [PATCH] homebrew comments system --- .env.example | 6 +- .prettierignore | 1 + README.md | 4 +- app/api/auth/[...all]/route.ts | 4 + app/api/hits/route.ts | 9 +- app/cli/page.mdx | 5 - app/contact/page.tsx | 3 +- app/layout.tsx | 3 + app/notes/[slug]/page.tsx | 48 +- app/notes/page.tsx | 14 +- app/previously/page.mdx | 21 +- app/privacy/page.mdx | 8 +- app/projects/page.tsx | 13 +- app/uses/page.mdx | 5 - app/zip/page.mdx | 5 - components/activity-calendar.tsx | 4 +- components/comments.tsx | 34 - components/comments/comment-actions.tsx | 96 + components/comments/comment-form.tsx | 194 ++ components/comments/comment-single.tsx | 71 + components/comments/comment-thread.tsx | 40 + components/comments/comments-skeleton.tsx | 26 + components/comments/comments.tsx | 64 + components/comments/sign-in.tsx | 35 + .../form.tsx => components/contact-form.tsx | 16 +- components/icons.tsx | 53 + components/layout/footer.tsx | 12 +- components/layout/header.tsx | 2 +- components/relative-time.tsx | 25 +- components/time.tsx | 27 - components/ui/alert-dialog.tsx | 112 ++ components/ui/avatar.tsx | 33 + components/ui/button.tsx | 2 +- components/ui/dropdown-menu.tsx | 221 +++ components/ui/popover.tsx | 41 + components/ui/separator.tsx | 27 + components/ui/skeleton.tsx | 8 + components/ui/sonner.tsx | 21 + components/view-counter.tsx | 9 +- drizzle.config.ts | 11 + eslint.config.mjs | 10 +- lib/auth-client.ts | 8 + lib/auth.ts | 31 + lib/date.ts | 13 + lib/db/index.ts | 6 + lib/db/migrations/0000_puzzling_sphinx.sql | 68 + lib/db/migrations/meta/0000_snapshot.json | 443 +++++ lib/db/migrations/meta/_journal.json | 13 + lib/db/schema.ts | 70 + lib/env.ts | 63 +- lib/posts.ts | 58 +- lib/rehype.ts | 1 + lib/server/comments.ts | 143 ++ app/projects/api.ts => lib/server/github.ts | 5 +- app/contact/action.ts => lib/server/resend.ts | 8 +- lib/server/views.ts | 85 + next.config.ts | 7 +- notes/coronavirus-open-source/index.mdx | 11 +- package.json | 31 +- pnpm-lock.yaml | 1601 ++++++++++++++++- public/humans.txt | 5 +- 61 files changed, 3616 insertions(+), 397 deletions(-) create mode 100644 app/api/auth/[...all]/route.ts delete mode 100644 components/comments.tsx create mode 100644 components/comments/comment-actions.tsx create mode 100644 components/comments/comment-form.tsx create mode 100644 components/comments/comment-single.tsx create mode 100644 components/comments/comment-thread.tsx create mode 100644 components/comments/comments-skeleton.tsx create mode 100644 components/comments/comments.tsx create mode 100644 components/comments/sign-in.tsx rename app/contact/form.tsx => components/contact-form.tsx (86%) create mode 100644 components/icons.tsx delete mode 100644 components/time.tsx create mode 100644 components/ui/alert-dialog.tsx create mode 100644 components/ui/avatar.tsx create mode 100644 components/ui/dropdown-menu.tsx create mode 100644 components/ui/popover.tsx create mode 100644 components/ui/separator.tsx create mode 100644 components/ui/skeleton.tsx create mode 100644 components/ui/sonner.tsx create mode 100644 drizzle.config.ts create mode 100644 lib/auth-client.ts create mode 100644 lib/auth.ts create mode 100644 lib/date.ts create mode 100644 lib/db/index.ts create mode 100644 lib/db/migrations/0000_puzzling_sphinx.sql create mode 100644 lib/db/migrations/meta/0000_snapshot.json create mode 100644 lib/db/migrations/meta/_journal.json create mode 100644 lib/db/schema.ts create mode 100644 lib/server/comments.ts rename app/projects/api.ts => lib/server/github.ts (93%) rename app/contact/action.ts => lib/server/resend.ts (91%) create mode 100644 lib/server/views.ts diff --git a/.env.example b/.env.example index 93a9058f..8c033865 100644 --- a/.env.example +++ b/.env.example @@ -3,6 +3,10 @@ # See lib/env.ts for the list of required environment variables and how to get them. ############### +AUTH_GITHUB_CLIENT_ID= +AUTH_GITHUB_CLIENT_SECRET= +AUTH_SECRET= +DATABASE_URL= GITHUB_TOKEN= KV_REST_API_TOKEN= KV_REST_API_URL= @@ -11,8 +15,6 @@ RESEND_FROM_EMAIL= RESEND_TO_EMAIL= TURNSTILE_SECRET_KEY= NEXT_PUBLIC_BASE_URL= -NEXT_PUBLIC_GISCUS_CATEGORY_ID= -NEXT_PUBLIC_GISCUS_REPO_ID= NEXT_PUBLIC_GITHUB_REPO= NEXT_PUBLIC_ONION_DOMAIN= NEXT_PUBLIC_SITE_LOCALE= diff --git a/.prettierignore b/.prettierignore index b87eae66..5053ae69 100644 --- a/.prettierignore +++ b/.prettierignore @@ -8,6 +8,7 @@ pnpm-lock.yaml .vercel/ # other +lib/db/migrations/ public/ .devcontainer/devcontainer.json .vscode/ diff --git a/README.md b/README.md index 96ce4057..398ca90b 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![GitHub repo size](https://img.shields.io/github/repo-size/jakejarvis/jarv.is?color=009cdf&label=repo%20size&logo=git&logoColor=white)](https://github.com/jakejarvis/jarv.is) [![Dynamic JSON Badge](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fjarv.is%2Fapi%2Fhits&query=%24.total.hits&logo=googleanalytics&logoColor=white&label=hits&color=salmon&cacheSeconds=1800)](https://jarv.is/api/hits) -My humble abode on the World Wide Web, created and deployed using [Next.js](https://nextjs.org/), [Tailwind CSS](https://github.com/user-attachments/assets/dfe99976-c73d-46f1-8a50-f26338463ad8), [Upstash](https://upstash.com/), [Giscus](https://giscus.app/), [and more](https://jarv.is/humans.txt). +My humble abode on the World Wide Web, created and deployed using [Next.js](https://nextjs.org/), [Tailwind CSS](https://github.com/user-attachments/assets/dfe99976-c73d-46f1-8a50-f26338463ad8), [Neon Postgres](https://neon.tech/), [Drizzle](https://orm.drizzle.team/), [Better Auth](https://www.better-auth.com/), [and more](https://jarv.is/humans.txt). ## 🕹️ Getting Started @@ -14,7 +14,7 @@ My humble abode on the World Wide Web, created and deployed using [Next.js](http I highly recommend spinning up a [Codespace](https://github.com/features/codespaces) with the button above to start inside of a preconfigured and tested environment. But you can also clone this repository locally, run `pnpm install` to pull down the necessary dependencies and `pnpm dev` to start the local server, and then open [localhost:3000](http://localhost:3000/) in a browser. Pages will live-refresh when source files are changed. -**Be sure to populate the required environment variables!** Refer to [`lib/env.ts`](lib/env.ts), which documents (and strictly [type-checks](https://env.t3.gg/docs/introduction)) these variables. The included [`.env.example`](.env.example) file should be copied and used as a template for a new `.env.local` file, which the local `next dev` server will then ingest. +**Be sure to populate the required environment variables!** Refer to [`lib/env.ts`](lib/env.ts), which documents (and strictly [type-checks](https://env.t3.gg/docs/introduction)) these variables. The included [`.env.example`](.env.example) file should be copied and used as a template for a new local `.env` file, which the local `next dev` server will then ingest. > ⚠️ **Currently, there are a few assumptions sprinkled throughout the code that this repo will be deployed to [Vercel](https://nextjs.org/docs/app/building-your-application/deploying#managed-nextjs-with-vercel) and _only_ Vercel.** I'll correct this soon™ now that some escape hatches (namely [OpenNext](https://opennext.js.org/)) actually exist... diff --git a/app/api/auth/[...all]/route.ts b/app/api/auth/[...all]/route.ts new file mode 100644 index 00000000..7cbe91bb --- /dev/null +++ b/app/api/auth/[...all]/route.ts @@ -0,0 +1,4 @@ +import { auth } from "@/lib/auth"; +import { toNextJsHandler } from "better-auth/next-js"; + +export const { POST, GET } = toNextJsHandler(auth); diff --git a/app/api/hits/route.ts b/app/api/hits/route.ts index f67f77f3..dd4fdbff 100644 --- a/app/api/hits/route.ts +++ b/app/api/hits/route.ts @@ -1,7 +1,6 @@ import { NextResponse } from "next/server"; import { unstable_cache as cache } from "next/cache"; -import { getViews as _getViews } from "@/lib/posts"; -import { POSTS_DIR } from "@/lib/config/constants"; +import { getViews as _getViews } from "@/lib/server/views"; const getViews = cache(_getViews, undefined, { revalidate: 300, // 5 minutes @@ -25,9 +24,9 @@ export const GET = async (): Promise< const total = { hits: Object.values(views).reduce((acc, curr) => acc + curr, 0), }; - const pages = Object.entries(views).map(([slug, hits]) => ({ - slug: `${POSTS_DIR}/${slug}`, - hits, + const pages = Object.entries(views).map(([slug, views]) => ({ + slug, + hits: views, })); pages.sort((a, b) => b.hits - a.hits); diff --git a/app/cli/page.mdx b/app/cli/page.mdx index 085158ba..ce32e7ea 100644 --- a/app/cli/page.mdx +++ b/app/cli/page.mdx @@ -1,5 +1,4 @@ import PageTitle from "@/components/layout/page-title"; -import Comments from "@/components/comments"; import { createMetadata } from "@/lib/metadata"; export const metadata = createMetadata({ @@ -35,7 +34,3 @@ npx @jakejarvis/cli ## License MIT © [Jake Jarvis](https://jarv.is/), [Sindre Sorhus](https://sindresorhus.com/) - ---- - - diff --git a/app/contact/page.tsx b/app/contact/page.tsx index da440efb..8ef846a9 100644 --- a/app/contact/page.tsx +++ b/app/contact/page.tsx @@ -1,9 +1,8 @@ import PageTitle from "@/components/layout/page-title"; import Link from "@/components/link"; +import ContactForm from "@/components/contact-form"; import { createMetadata } from "@/lib/metadata"; -import ContactForm from "./form"; - export const metadata = createMetadata({ title: "Contact Me", description: "Fill out this quick form and I'll get back to you as soon as I can.", diff --git a/app/layout.tsx b/app/layout.tsx index 75019cd3..9beab455 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -5,6 +5,7 @@ import { ThemeProvider, ThemeScript } from "@/components/layout/theme-context"; import Header from "@/components/layout/header"; import Footer from "@/components/layout/footer"; import SkipNavButton, { SKIP_NAV_ID } from "@/components/layout/skip-nav"; +import Toaster from "@/components/ui/sonner"; import { defaultMetadata } from "@/lib/metadata"; import { GeistMono, GeistSans } from "@/lib/fonts"; import siteConfig from "@/lib/config/site"; @@ -73,6 +74,8 @@ const RootLayout = ({ children }: Readonly<{ children: React.ReactNode }>) => {