1
mirror of https://github.com/jakejarvis/jarv.is.git synced 2026-06-05 19:15:30 -04:00

re-enable comments on non-post pages

This commit is contained in:
2025-05-18 14:38:10 -04:00
parent 3f56632313
commit a9d83768ca
19 changed files with 211 additions and 83 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
import { NextResponse } from "next/server";
import { unstable_cache as cache } from "next/cache";
import { getViews as _getViews } from "@/lib/server/views";
import { getViews as _getViews } from "@/lib/views";
const getViews = cache(_getViews, undefined, {
revalidate: 300, // 5 minutes
+9
View File
@@ -1,4 +1,7 @@
import { Suspense } from "react";
import PageTitle from "@/components/layout/page-title";
import Comments from "@/components/comments/comments";
import CommentsSkeleton from "@/components/comments/comments-skeleton";
import { createMetadata } from "@/lib/metadata";
export const metadata = createMetadata({
@@ -7,6 +10,8 @@ export const metadata = createMetadata({
canonical: "/cli",
});
export const experimental_ppr = true;
<PageTitle canonical="/cli">CLI</PageTitle>
> The [Jake Jarvis](https://jarv.is/) CLI (aka the most useless Node module ever published, in history, by anyone, ever).
@@ -34,3 +39,7 @@ npx @jakejarvis/cli
## License
MIT &copy; [Jake Jarvis](https://jarv.is/), [Sindre Sorhus](https://sindresorhus.com/)
<Suspense fallback={<CommentsSkeleton />}>
<Comments slug="uses" />
</Suspense>
+1 -2
View File
@@ -3,9 +3,8 @@ import path from "path";
import fs from "fs";
import { ImageResponse } from "next/og";
import { notFound } from "next/navigation";
import { getSlugs, getFrontMatter } from "@/lib/posts";
import { getSlugs, getFrontMatter, POSTS_DIR } from "@/lib/posts";
import siteConfig from "@/lib/config/site";
import { POSTS_DIR } from "@/lib/config/constants";
export const contentType = "image/png";
export const size = {
+4 -9
View File
@@ -7,11 +7,10 @@ import Link from "@/components/link";
import ViewCounter from "@/components/view-counter";
import Comments from "@/components/comments/comments";
import CommentsSkeleton from "@/components/comments/comments-skeleton";
import { getSlugs, getFrontMatter } from "@/lib/posts";
import { getSlugs, getFrontMatter, POSTS_DIR } from "@/lib/posts";
import { createMetadata } from "@/lib/metadata";
import siteConfig from "@/lib/config/site";
import authorConfig from "@/lib/config/author";
import { POSTS_DIR } from "@/lib/config/constants";
import { size as ogImageSize } from "./opengraph-image";
import type { Metadata } from "next";
import type { BlogPosting } from "schema-dts";
@@ -143,13 +142,9 @@ const Page = async ({ params }: { params: Promise<{ slug: string }> }) => {
<MDXContent />
<section id="comments" className="isolate mt-8 mb-10 min-h-36 w-full border-t-2 pt-8">
<div className="mx-auto w-full max-w-3xl">
<Suspense fallback={<CommentsSkeleton />}>
<Comments slug={`${POSTS_DIR}/${frontmatter!.slug}`} closed={frontmatter!.noComments} />
</Suspense>
</div>
</section>
<Suspense fallback={<CommentsSkeleton />}>
<Comments slug={`${POSTS_DIR}/${frontmatter!.slug}`} closed={frontmatter!.noComments} />
</Suspense>
</>
);
};
+3 -4
View File
@@ -1,16 +1,15 @@
import { env } from "@/lib/env";
import { EyeIcon } from "lucide-react";
import Link from "@/components/link";
import { getFrontMatter } from "@/lib/posts";
import { getFrontMatter, POSTS_DIR } from "@/lib/posts";
import { createMetadata } from "@/lib/metadata";
import { formatDate, formatDateISO } from "@/lib/date";
import authorConfig from "@/lib/config/author";
import { POSTS_DIR } from "@/lib/config/constants";
import { getViews } from "@/lib/server/views";
import { getViews } from "@/lib/views";
import type { ReactElement } from "react";
import type { FrontMatter } from "@/lib/posts";
export const revalidate = 600; // 10 minutes
export const revalidate = 300; // 5 minutes
export const metadata = createMetadata({
title: "Notes",
+143
View File
@@ -0,0 +1,143 @@
import "server-only";
import { env } from "@/lib/env";
import * as cheerio from "cheerio";
import { graphql } from "@octokit/graphql";
import type { Repository, User } from "@octokit/graphql-schema";
export const getContributions = async (): Promise<
Array<{
date: string;
count: number;
level: number;
}>
> => {
// thanks @grubersjoe! :) https://github.com/grubersjoe/github-contributions-api/blob/main/src/scrape.ts
try {
const response = await fetch(`https://github.com/users/${env.NEXT_PUBLIC_GITHUB_USERNAME}/contributions`, {
headers: {
referer: `https://github.com/${env.NEXT_PUBLIC_GITHUB_USERNAME}`,
"x-requested-with": "XMLHttpRequest",
},
cache: "force-cache",
next: {
revalidate: 900, // 15 minutes
tags: ["github-contributions"],
},
});
const $ = cheerio.load(await response.text());
const days = $(".js-calendar-graph-table .ContributionCalendar-day")
.get()
.sort((a, b) => {
const dateA = a.attribs["data-date"] ?? "";
const dateB = b.attribs["data-date"] ?? "";
return dateA.localeCompare(dateB, "en");
});
const dayTooltips = $(".js-calendar-graph tool-tip")
.toArray()
// eslint-disable-next-line @typescript-eslint/no-explicit-any
.reduce<Record<string, any>>((map, elem) => {
map[elem.attribs["for"]] = elem;
return map;
}, {});
return days.map((day) => {
const attr = {
id: day.attribs["id"],
date: day.attribs["data-date"],
level: day.attribs["data-level"],
};
let count = 0;
if (dayTooltips[attr.id]) {
const text = dayTooltips[attr.id].firstChild;
if (text) {
const countMatch = text.data.trim().match(/^\d+/);
if (countMatch) {
count = parseInt(countMatch[0]);
}
}
}
const level = parseInt(attr.level);
return {
date: attr.date,
count,
level,
};
});
} catch (error) {
console.error("[server/github] Failed to fetch contributions:", error);
return [];
}
};
export const getRepos = async (): Promise<Repository[] | undefined> => {
try {
// https://docs.github.com/en/graphql/reference/objects#repository
const { user } = await graphql<{ user: User }>(
`
query ($username: String!, $sort: RepositoryOrderField!, $limit: Int) {
user(login: $username) {
repositories(
first: $limit
isLocked: false
isFork: false
ownerAffiliations: OWNER
privacy: PUBLIC
orderBy: { field: $sort, direction: DESC }
) {
edges {
node {
name
url
description
pushedAt
stargazerCount
forkCount
primaryLanguage {
name
color
}
}
}
}
}
}
`,
{
username: env.NEXT_PUBLIC_GITHUB_USERNAME,
sort: "STARGAZERS",
limit: 12,
headers: {
accept: "application/vnd.github.v3+json",
authorization: `token ${env.GITHUB_TOKEN}`,
},
request: {
// override fetch() to use next's extension to cache the response
// https://nextjs.org/docs/app/api-reference/functions/fetch#fetchurl-options
fetch: (url: string | URL | Request, options?: RequestInit) => {
return fetch(url, {
...options,
cache: "force-cache",
next: {
revalidate: 900, // 15 minutes
tags: ["github-repos"],
},
});
},
},
}
);
return user.repositories.edges?.map((edge) => edge!.node as Repository);
} catch (error) {
console.error("[server/github] Failed to fetch repositories:", error);
return [];
}
};
+1 -1
View File
@@ -9,7 +9,7 @@ import ActivityCalendar from "@/components/activity-calendar";
import { GitHubIcon } from "@/components/icons";
import { cn } from "@/lib/utils";
import { createMetadata } from "@/lib/metadata";
import { getContributions, getRepos } from "@/lib/server/github";
import { getContributions, getRepos } from "./github";
export const metadata = createMetadata({
title: "Projects",
+9
View File
@@ -1,4 +1,7 @@
import { Suspense } from "react";
import PageTitle from "@/components/layout/page-title";
import Comments from "@/components/comments/comments";
import CommentsSkeleton from "@/components/comments/comments-skeleton";
import { createMetadata } from "@/lib/metadata";
export const metadata = createMetadata({
@@ -7,6 +10,8 @@ export const metadata = createMetadata({
canonical: "/uses",
});
export const experimental_ppr = true;
<PageTitle canonical="/uses">Uses</PageTitle>
~~I regularly get messages asking about which tools I use to work.~~
@@ -164,3 +169,7 @@ Other geeky stuff:
- 2x [**ecobee3 lite**](https://www.ecobee.com/en-us/smart-thermostats/smart-wifi-thermostat/)
- 2x [**Sonos One**](https://www.sonos.com/en-us/shop/one.html) (with Alexa turned off...hopefully? 🤫)
- 2x [**Apple TV 4K** (2021)](https://www.apple.com/apple-tv-4k/)
<Suspense fallback={<CommentsSkeleton />}>
<Comments slug="uses" />
</Suspense>
+9
View File
@@ -1,4 +1,7 @@
import { Suspense } from "react";
import PageTitle from "@/components/layout/page-title";
import Comments from "@/components/comments/comments";
import CommentsSkeleton from "@/components/comments/comments-skeleton";
import { createMetadata } from "@/lib/metadata";
import backgroundImg from "./sundar.jpg";
@@ -9,6 +12,8 @@ export const metadata = createMetadata({
canonical: "/zip",
});
export const experimental_ppr = true;
export const Terminal = () => (
<div
className="relative mx-auto my-6 w-full rounded-lg"
@@ -71,3 +76,7 @@ A little-known monopolistic internet conglomorate simply unleashed [multiple](ht
- **Kaspersky:** [Beware the .zip and .mov domains!](https://usa.kaspersky.com/blog/zip-mov-domain-extension-confusion/28351/)
- **Palo Alto Networks:** [New Top Level Domains .zip and .mov open the door for new attacks](https://knowledgebase.paloaltonetworks.com/KCSArticleDetail?id=kA14u000000g1wOCAQ)
- **Google, twenty years ago:** ["Don't be evil"](https://web.archive.org/web/20050204181615/http://investor.google.com/conduct.html)
<Suspense fallback={<CommentsSkeleton />}>
<Comments slug="zip" />
</Suspense>