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:
@@ -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
|
||||
|
||||
@@ -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 © [Jake Jarvis](https://jarv.is/), [Sindre Sorhus](https://sindresorhus.com/)
|
||||
|
||||
<Suspense fallback={<CommentsSkeleton />}>
|
||||
<Comments slug="uses" />
|
||||
</Suspense>
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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
@@ -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",
|
||||
|
||||
@@ -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 [];
|
||||
}
|
||||
};
|
||||
@@ -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",
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user