mirror of
https://github.com/jakejarvis/jarv.is.git
synced 2025-04-26 04:45:22 -04:00
a bit more cleanup
This commit is contained in:
parent
354dade9aa
commit
9229f92c0c
25
.env.example
25
.env.example
@ -1,25 +1,32 @@
|
||||
# required. storage for hit counter endpoints at /api/count and /api/hits.
|
||||
# currently uses Postgres, but this can be changed in prisma/schema.prisma.
|
||||
# required. storage for hit counter's server component at app/notes/[slug]/counter.tsx and API endpoint at /api/hits.
|
||||
# currently set automatically by Vercel's Neon integration, but this can be changed in prisma/schema.prisma.
|
||||
# https://www.prisma.io/docs/postgres/overview
|
||||
# https://vercel.com/marketplace/neon
|
||||
DATABASE_URL=
|
||||
|
||||
# requred. used for /projects grid, built with SSG. only needs the "public_repo" scope since we don't need/want to
|
||||
# required. used for /projects grid, built with ISR. only needs the "public_repo" scope since we don't need/want to
|
||||
# showcase any private repositories, obviously.
|
||||
# https://github.com/settings/tokens/new?scopes=public_repo
|
||||
GH_PUBLIC_TOKEN=
|
||||
GITHUB_TOKEN=
|
||||
|
||||
# required for production. sends contact form submissions via /api/contact.
|
||||
# optional. enables comments on blog posts via GitHub discussions.
|
||||
# https://giscus.app/
|
||||
NEXT_PUBLIC_GISCUS_REPO_ID=
|
||||
NEXT_PUBLIC_GISCUS_CATEGORY_ID=
|
||||
|
||||
# required for production. sends contact form submissions via a server action (see app/contact/actions.ts).
|
||||
# https://resend.com/api-keys
|
||||
# currently set automatically by Vercel's Resend integration.
|
||||
# https://vercel.com/integrations/resend
|
||||
RESEND_API_KEY=
|
||||
# optional. send submissions from noreply@{RESEND_DOMAIN}; defaults to onboarding@resend.dev. sender's real email is
|
||||
# passed via a Reply-To header. setting this makes zero difference to the user.
|
||||
# https://resend.com/docs/send-with-nodemailer-smtp
|
||||
RESEND_DOMAIN=
|
||||
|
||||
# required for production. falls back to testing keys if not set or in dev environment:
|
||||
# required for production. site key must be prefixed with NEXT_PUBLIC_ since it is used to embed the captcha widget.
|
||||
# falls back to testing keys if not set or in dev environment:
|
||||
# https://developers.cloudflare.com/turnstile/troubleshooting/testing/
|
||||
# site key must be prefixed with NEXT_PUBLIC_ since it is used to embed the actual captcha widget.
|
||||
# https://developers.cloudflare.com/turnstile/
|
||||
NEXT_PUBLIC_TURNSTILE_SITE_KEY=
|
||||
# used only for backend validation of contact form submissions on /api/contact.
|
||||
# used for backend validation of turnstile result.
|
||||
TURNSTILE_SECRET_KEY=
|
||||
|
@ -3,7 +3,7 @@
|
||||
import { headers } from "next/headers";
|
||||
import { z } from "zod";
|
||||
import { Resend } from "resend";
|
||||
import config from "../../lib/config";
|
||||
import config from "../../lib/config/constants";
|
||||
|
||||
const schema = z.object({
|
||||
name: z.string().min(1, { message: "Name is required" }),
|
||||
|
@ -3,7 +3,7 @@ import { buildFeed } from "../../lib/helpers/build-feed";
|
||||
export const dynamic = "force-static";
|
||||
|
||||
export const GET = async () => {
|
||||
return new Response(await buildFeed({ type: "atom" }), {
|
||||
return new Response((await buildFeed()).atom1(), {
|
||||
headers: {
|
||||
"content-type": "application/atom+xml; charset=utf-8",
|
||||
},
|
||||
|
@ -3,7 +3,7 @@ import { buildFeed } from "../../lib/helpers/build-feed";
|
||||
export const dynamic = "force-static";
|
||||
|
||||
export const GET = async () => {
|
||||
return new Response(await buildFeed({ type: "rss" }), {
|
||||
return new Response((await buildFeed()).rss2(), {
|
||||
headers: {
|
||||
"content-type": "application/rss+xml; charset=utf-8",
|
||||
},
|
||||
|
@ -4,7 +4,7 @@ import { ThemeProvider } from "../contexts/ThemeContext";
|
||||
import Header from "../components/Header";
|
||||
import Footer from "../components/Footer";
|
||||
import { SkipToContentLink, SkipToContentTarget } from "../components/SkipToContent";
|
||||
import config from "../lib/config";
|
||||
import config from "../lib/config/constants";
|
||||
import type { Metadata } from "next";
|
||||
import type { Person, WithContext } from "schema-dts";
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import config from "../lib/config";
|
||||
import config from "../lib/config/constants";
|
||||
import type { MetadataRoute } from "next";
|
||||
|
||||
const manifest = (): MetadataRoute.Manifest => {
|
||||
|
@ -8,7 +8,7 @@ import Loading from "../../../components/Loading";
|
||||
import HitCounter from "./counter";
|
||||
import { getPostSlugs, getFrontMatter } from "../../../lib/helpers/posts";
|
||||
import { metadata as defaultMetadata } from "../../layout";
|
||||
import config from "../../../lib/config";
|
||||
import config from "../../../lib/config/constants";
|
||||
import { FiCalendar, FiTag, FiEdit, FiEye } from "react-icons/fi";
|
||||
import type { Metadata, Route } from "next";
|
||||
import type { Article, WithContext } from "schema-dts";
|
||||
|
@ -2,7 +2,7 @@ import Content from "../../components/Content";
|
||||
import Link from "../../components/Link";
|
||||
import Time from "../../components/Time";
|
||||
import { getAllPosts } from "../../lib/helpers/posts";
|
||||
import config from "../../lib/config";
|
||||
import config from "../../lib/config/constants";
|
||||
import { metadata as defaultMetadata } from "../layout";
|
||||
import type { ReactElement } from "react";
|
||||
import type { Metadata, Route } from "next";
|
||||
|
@ -4,7 +4,7 @@ import PageTitle from "../../components/PageTitle";
|
||||
import Link from "../../components/Link";
|
||||
import RelativeTime from "../../components/RelativeTime";
|
||||
import commaNumber from "comma-number";
|
||||
import config from "../../lib/config";
|
||||
import config from "../../lib/config/constants";
|
||||
import { metadata as defaultMetadata } from "../layout";
|
||||
import { GoStar, GoRepoForked } from "react-icons/go";
|
||||
import { SiGithub } from "react-icons/si";
|
||||
@ -43,8 +43,8 @@ type Project = {
|
||||
|
||||
async function getRepos(): Promise<Project[] | null> {
|
||||
// don't fail the entire site build if the required API key for this page is missing
|
||||
if (!process.env.GH_PUBLIC_TOKEN || process.env.GH_PUBLIC_TOKEN === "") {
|
||||
console.warn(`ERROR: I can't fetch any GitHub projects without "GH_PUBLIC_TOKEN" set! Skipping for now...`);
|
||||
if (!process.env.GITHUB_TOKEN || process.env.GITHUB_TOKEN === "") {
|
||||
console.warn(`ERROR: I can't fetch any GitHub projects without "GITHUB_TOKEN" set! Skipping for now...`);
|
||||
|
||||
return null;
|
||||
}
|
||||
@ -86,7 +86,7 @@ async function getRepos(): Promise<Project[] | null> {
|
||||
limit: 12,
|
||||
headers: {
|
||||
accept: "application/vnd.github.v3+json",
|
||||
authorization: `token ${process.env.GH_PUBLIC_TOKEN}`,
|
||||
authorization: `token ${process.env.GITHUB_TOKEN}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import config from "../lib/config";
|
||||
import config from "../lib/config/constants";
|
||||
import type { MetadataRoute } from "next";
|
||||
|
||||
export const dynamic = "force-static";
|
||||
|
@ -1,7 +1,7 @@
|
||||
import path from "path";
|
||||
import glob from "fast-glob";
|
||||
import { getAllPosts } from "../lib/helpers/posts";
|
||||
import config from "../lib/config";
|
||||
import config from "../lib/config/constants";
|
||||
import type { MetadataRoute } from "next";
|
||||
|
||||
export const dynamic = "force-static";
|
||||
|
@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import Giscus from "@giscus/react";
|
||||
import config from "../../lib/config";
|
||||
import config from "../../lib/config/constants";
|
||||
import type { GiscusProps } from "@giscus/react";
|
||||
|
||||
export type CommentsProps = {
|
||||
@ -10,9 +10,9 @@ export type CommentsProps = {
|
||||
|
||||
const Comments = ({ title }: CommentsProps) => {
|
||||
// fail silently if giscus isn't configured
|
||||
if (!config.giscusConfig) {
|
||||
if (!process.env.NEXT_PUBLIC_GISCUS_REPO_ID || !process.env.NEXT_PUBLIC_GISCUS_CATEGORY_ID) {
|
||||
console.warn(
|
||||
"[giscus] not configured, ensure giscusConfig.repoId and giscusConfig.categoryId are set in lib/config/index.js"
|
||||
"[giscus] not configured, ensure 'NEXT_PUBLIC_GISCUS_REPO_ID' and 'NEXT_PUBLIC_GISCUS_CATEGORY_ID' environment variables are set."
|
||||
);
|
||||
|
||||
return null;
|
||||
@ -22,14 +22,15 @@ const Comments = ({ title }: CommentsProps) => {
|
||||
return (
|
||||
<Giscus
|
||||
repo={config.githubRepo as GiscusProps["repo"]}
|
||||
repoId={config.giscusConfig.repoId}
|
||||
repoId={process.env.NEXT_PUBLIC_GISCUS_REPO_ID}
|
||||
term={title}
|
||||
category="Comments"
|
||||
categoryId={config.giscusConfig.categoryId}
|
||||
categoryId={process.env.NEXT_PUBLIC_GISCUS_CATEGORY_ID}
|
||||
mapping="specific"
|
||||
reactionsEnabled="1"
|
||||
emitMetadata="0"
|
||||
inputPosition="top"
|
||||
theme="preferred_color_scheme"
|
||||
loading="lazy"
|
||||
/>
|
||||
);
|
||||
|
@ -2,7 +2,7 @@ import clsx from "clsx";
|
||||
import Link from "../Link";
|
||||
import { GoHeartFill } from "react-icons/go";
|
||||
import { SiNextdotjs } from "react-icons/si";
|
||||
import config from "../../lib/config";
|
||||
import config from "../../lib/config/constants";
|
||||
import type { ComponentPropsWithoutRef } from "react";
|
||||
|
||||
import styles from "./Footer.module.css";
|
||||
|
@ -2,7 +2,7 @@ import clsx from "clsx";
|
||||
import Link from "../Link";
|
||||
import Image from "../Image";
|
||||
import Menu from "../Menu";
|
||||
import config from "../../lib/config";
|
||||
import config from "../../lib/config/constants";
|
||||
import type { ComponentPropsWithoutRef } from "react";
|
||||
|
||||
import styles from "./Header.module.css";
|
||||
|
@ -1,7 +1,7 @@
|
||||
import NextLink from "next/link";
|
||||
import clsx from "clsx";
|
||||
import objStr from "obj-str";
|
||||
import config from "../../lib/config";
|
||||
import config from "../../lib/config/constants";
|
||||
import type { ComponentPropsWithoutRef } from "react";
|
||||
|
||||
import styles from "./Link.module.css";
|
||||
|
@ -35,10 +35,11 @@ const Video = ({ src, poster, autoplay = false, responsive = true, className, ..
|
||||
>
|
||||
{src.map((file) => {
|
||||
const extension = file.split(".").pop();
|
||||
|
||||
if (extension === "vtt") {
|
||||
return <track key={file} kind="subtitles" src={file} srcLang="en" label="English" default />;
|
||||
} else {
|
||||
return <source key={file} src={file} type={`video/${file.split(".").pop()}`} />;
|
||||
return <source key={file} src={file} type={`video/${extension}`} />;
|
||||
}
|
||||
})}
|
||||
</video>
|
||||
|
@ -1,6 +1,4 @@
|
||||
// @ts-check
|
||||
|
||||
const config = {
|
||||
const constants = {
|
||||
// Site info
|
||||
siteName: "Jake Jarvis",
|
||||
siteLocale: "en-US",
|
||||
@ -20,11 +18,6 @@ const config = {
|
||||
licenseUrl: "https://creativecommons.org/licenses/by/4.0/",
|
||||
copyrightYearStart: 2001,
|
||||
githubRepo: "jakejarvis/jarv.is",
|
||||
giscusConfig: {
|
||||
// https://github.com/giscus/giscus-component/tree/main/packages/react#readme
|
||||
repoId: "MDEwOlJlcG9zaXRvcnk1MzM0MDgxMQ==",
|
||||
categoryId: "DIC_kwDOAy3qi84CAsjS",
|
||||
},
|
||||
|
||||
// Me info
|
||||
authorName: "Jake Jarvis",
|
||||
@ -42,4 +35,4 @@ const config = {
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
export default constants;
|
@ -1,10 +1,10 @@
|
||||
import { Feed } from "feed";
|
||||
import { getAllPosts } from "./posts";
|
||||
import config from "../config";
|
||||
import config from "../config/constants";
|
||||
|
||||
import meJpg from "../../app/me.jpg";
|
||||
|
||||
export const buildFeed = async (options: { type: "rss" | "atom" | "json" }): Promise<string> => {
|
||||
export const buildFeed = async (): Promise<Feed> => {
|
||||
// https://github.com/jpmonette/feed#example
|
||||
const feed = new Feed({
|
||||
id: config.baseUrl,
|
||||
@ -43,15 +43,5 @@ export const buildFeed = async (options: { type: "rss" | "atom" | "json" }): Pro
|
||||
});
|
||||
});
|
||||
|
||||
if (options.type === "rss") {
|
||||
return feed.rss2();
|
||||
} else if (options.type === "atom") {
|
||||
return feed.atom1();
|
||||
} else if (options.type === "json") {
|
||||
// rare but including as an option because why not...
|
||||
// https://www.jsonfeed.org/
|
||||
return feed.json1();
|
||||
} else {
|
||||
throw new TypeError(`Invalid feed type "${options.type}", must be "rss", "atom", or "json".`);
|
||||
}
|
||||
return feed;
|
||||
};
|
||||
|
@ -5,7 +5,7 @@ import dayjsRelativeTime from "dayjs/plugin/relativeTime";
|
||||
import dayjsLocalizedFormat from "dayjs/plugin/localizedFormat";
|
||||
import dayjsAdvancedFormat from "dayjs/plugin/advancedFormat";
|
||||
import "dayjs/locale/en";
|
||||
import config from "../config";
|
||||
import config from "../config/constants";
|
||||
|
||||
const IsomorphicDayJs = (date?: dayjs.ConfigType): dayjs.Dayjs => {
|
||||
// plugins
|
||||
|
@ -3,7 +3,7 @@ import glob from "fast-glob";
|
||||
import pMap from "p-map";
|
||||
import pMemoize from "p-memoize";
|
||||
import { formatDate } from "./format-date";
|
||||
import config from "../config";
|
||||
import config from "../config/constants";
|
||||
|
||||
// path to directory with .mdx files, relative to project root
|
||||
const POSTS_DIR = "notes";
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import type { NextRequest } from "next/server";
|
||||
|
||||
import siteConfig from "./lib/config";
|
||||
import siteConfig from "./lib/config/constants";
|
||||
|
||||
export function middleware(request: NextRequest) {
|
||||
const response = NextResponse.next();
|
||||
|
@ -28,7 +28,7 @@ const nextConfig: NextConfig = {
|
||||
},
|
||||
eslint: {
|
||||
// https://nextjs.org/docs/basic-features/eslint#linting-custom-directories-and-files
|
||||
dirs: ["app", "components", "contexts", "hooks", "lib"],
|
||||
dirs: ["app", "components", "contexts", "hooks", "lib", "notes"],
|
||||
},
|
||||
headers: async () => [
|
||||
{
|
||||
|
@ -101,7 +101,7 @@
|
||||
"engines": {
|
||||
"node": ">=20.x"
|
||||
},
|
||||
"packageManager": "pnpm@10.5.2+sha512.da9dc28cd3ff40d0592188235ab25d3202add8a207afbedc682220e4a0029ffbff4562102b9e6e46b4e3f9e8bd53e6d05de48544b0c57d4b0179e22c76d1199b",
|
||||
"packageManager": "pnpm@10.6.1+sha512.40ee09af407fa9fbb5fbfb8e1cb40fbb74c0af0c3e10e9224d7b53c7658528615b2c92450e74cfad91e3a2dcafe3ce4050d80bda71d757756d2ce2b66213e9a3",
|
||||
"cacheDirectories": [
|
||||
"node_modules",
|
||||
".next/cache"
|
||||
|
Loading…
x
Reference in New Issue
Block a user