mirror of
https://github.com/jakejarvis/jarv.is.git
synced 2026-06-05 19:15:30 -04:00
Tailwind redesign (#2387)
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
const authorConfig = {
|
||||
name: "Jake Jarvis",
|
||||
email: "jake@jarv.is",
|
||||
social: {
|
||||
github: "jakejarvis",
|
||||
twitter: "jakejarvis",
|
||||
facebook: "jakejarvis",
|
||||
medium: "jakejarvis",
|
||||
linkedin: "jakejarvis",
|
||||
instagram: "jakejarvis",
|
||||
mastodon: "fediverse.jarv.is/@jake",
|
||||
bluesky: "jarv.is",
|
||||
},
|
||||
} as const;
|
||||
|
||||
export default authorConfig;
|
||||
@@ -1,5 +1,5 @@
|
||||
/** Path to directory with .mdx files, relative to project root. */
|
||||
export const POSTS_DIR = "notes";
|
||||
export const POSTS_DIR = "notes" as const;
|
||||
|
||||
/** Maximum width of content wrapper (e.g. for images) in pixels. */
|
||||
export const MAX_WIDTH = 865;
|
||||
export const MAX_WIDTH = 896 as const;
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
// Site info
|
||||
export const siteName = "Jake Jarvis";
|
||||
export const tagline = "Frontend Web Developer in Boston, MA";
|
||||
export const description =
|
||||
"Hi there! I'm a frontend web developer based in Boston, Massachusetts specializing in TypeScript, React, Next.js, and other JavaScript frameworks.";
|
||||
export const license = "Creative Commons Attribution 4.0 International";
|
||||
export const licenseAbbr = "CC-BY-4.0";
|
||||
export const licenseUrl = "https://creativecommons.org/licenses/by/4.0/";
|
||||
export const copyrightYearStart = 2001;
|
||||
|
||||
// Me info
|
||||
export const authorName = "Jake Jarvis";
|
||||
export const authorEmail = "jake@jarv.is";
|
||||
export const authorSocial = {
|
||||
github: "jakejarvis",
|
||||
twitter: "jakejarvis",
|
||||
facebook: "jakejarvis",
|
||||
medium: "jakejarvis",
|
||||
linkedin: "jakejarvis",
|
||||
instagram: "jakejarvis",
|
||||
mastodon: "fediverse.jarv.is/@jake",
|
||||
bluesky: "jarv.is",
|
||||
};
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { CodeIcon, HomeIcon, MailIcon, PencilLineIcon } from "lucide-react";
|
||||
import type { MenuItemProps } from "../../components/MenuItem";
|
||||
import type { MenuItemProps } from "@/components/ui/menu-item";
|
||||
|
||||
export const menuItems: MenuItemProps[] = [
|
||||
{
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
const siteConfig = {
|
||||
name: "Jake Jarvis",
|
||||
tagline: "Frontend Web Developer in Boston, MA",
|
||||
description:
|
||||
"Hi there! I'm a frontend web developer based in Boston, Massachusetts specializing in TypeScript, React, Next.js, and other JavaScript frameworks.",
|
||||
license: "CC-BY-4.0",
|
||||
copyrightYearStart: 2001,
|
||||
} as const;
|
||||
|
||||
export default siteConfig;
|
||||
+11
-10
@@ -1,10 +1,11 @@
|
||||
import { env } from "../../lib/env";
|
||||
import { env } from "@/lib/env";
|
||||
import { Feed } from "feed";
|
||||
import { getFrontMatter, getContent } from "./posts";
|
||||
import * as config from "../config";
|
||||
import { getFrontMatter, getContent } from "@/lib/helpers/posts";
|
||||
import siteConfig from "@/lib/config/site";
|
||||
import authorConfig from "@/lib/config/author";
|
||||
import type { Item as FeedItem } from "feed";
|
||||
|
||||
import ogImage from "../../app/opengraph-image.jpg";
|
||||
import ogImage from "@/app/opengraph-image.jpg";
|
||||
|
||||
/**
|
||||
* Returns a `Feed` object, which can then be processed with `feed.rss2()`, `feed.atom1()`, or `feed.json1()`.
|
||||
@@ -14,9 +15,9 @@ export const buildFeed = async (): Promise<Feed> => {
|
||||
const feed = new Feed({
|
||||
id: `${env.NEXT_PUBLIC_BASE_URL}`,
|
||||
link: `${env.NEXT_PUBLIC_BASE_URL}`,
|
||||
title: config.siteName,
|
||||
description: config.description,
|
||||
copyright: config.licenseUrl,
|
||||
title: siteConfig.name,
|
||||
description: siteConfig.description,
|
||||
copyright: `https://spdx.org/licenses/${siteConfig.license}.html`,
|
||||
updated: new Date(),
|
||||
image: `${env.NEXT_PUBLIC_BASE_URL}${ogImage.src}`,
|
||||
feedLinks: {
|
||||
@@ -24,9 +25,9 @@ export const buildFeed = async (): Promise<Feed> => {
|
||||
atom: `${env.NEXT_PUBLIC_BASE_URL}/feed.atom`,
|
||||
},
|
||||
author: {
|
||||
name: config.authorName,
|
||||
name: authorConfig.name,
|
||||
link: env.NEXT_PUBLIC_BASE_URL,
|
||||
email: config.authorEmail,
|
||||
email: authorConfig.email,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -40,7 +41,7 @@ export const buildFeed = async (): Promise<Feed> => {
|
||||
description: post.description,
|
||||
author: [
|
||||
{
|
||||
name: config.authorName,
|
||||
name: authorConfig.name,
|
||||
link: `${env.NEXT_PUBLIC_BASE_URL}`,
|
||||
},
|
||||
],
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { h } from "hastscript";
|
||||
import { toString as nodeToString } from "hast-util-to-string";
|
||||
import type { ElementContent } from "hast";
|
||||
|
||||
const anchor = (heading: ElementContent) => [
|
||||
h(
|
||||
"span.anchor-icon",
|
||||
{
|
||||
ariaHidden: "true",
|
||||
},
|
||||
h(
|
||||
"svg",
|
||||
{
|
||||
width: 16,
|
||||
height: 16,
|
||||
viewBox: "0 0 16 16",
|
||||
xlmns: "http://www.w3.org/2000/svg",
|
||||
},
|
||||
h("path", {
|
||||
fillRule: "evenodd",
|
||||
fill: "currentcolor",
|
||||
d: "M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z",
|
||||
})
|
||||
)
|
||||
),
|
||||
h("span.sr-only", `Jump to "${nodeToString(heading)}"`),
|
||||
];
|
||||
|
||||
export default anchor;
|
||||
@@ -1 +0,0 @@
|
||||
export { default as recmaMdxEscapeMissingComponents } from "recma-mdx-escape-missing-components";
|
||||
@@ -1,4 +1,6 @@
|
||||
export { default as rehypeAutolinkHeadings } from "rehype-autolink-headings";
|
||||
export { default as rehypeMdxCodeProps } from "rehype-mdx-code-props";
|
||||
export { default as rehypeMdxImportMedia } from "rehype-mdx-import-media";
|
||||
export { default as rehypePrettyCode } from "rehype-pretty-code";
|
||||
export { default as rehypeSlug } from "rehype-slug";
|
||||
export { default as rehypeUnwrapImages } from "rehype-unwrap-images";
|
||||
export { default as rehypeWrapper } from "rehype-wrapper";
|
||||
|
||||
+12
-10
@@ -1,39 +1,41 @@
|
||||
import { env } from "../env";
|
||||
import * as config from "../config";
|
||||
import { env } from "@/lib/env";
|
||||
import siteConfig from "@/lib/config/site";
|
||||
import authorConfig from "@/lib/config/author";
|
||||
|
||||
import type { Metadata } from "next";
|
||||
|
||||
export const defaultMetadata: Metadata = {
|
||||
metadataBase: new URL(env.NEXT_PUBLIC_BASE_URL),
|
||||
title: {
|
||||
template: `%s – ${config.siteName}`,
|
||||
default: `${config.siteName} – ${config.tagline}`,
|
||||
template: `%s – ${siteConfig.name}`,
|
||||
default: `${siteConfig.name} – ${siteConfig.tagline}`,
|
||||
},
|
||||
description: config.description,
|
||||
description: siteConfig.description,
|
||||
openGraph: {
|
||||
siteName: config.siteName,
|
||||
siteName: siteConfig.name,
|
||||
title: {
|
||||
template: "%s",
|
||||
default: `${config.siteName} – ${config.tagline}`,
|
||||
default: `${siteConfig.name} – ${siteConfig.tagline}`,
|
||||
},
|
||||
url: "/",
|
||||
locale: env.NEXT_PUBLIC_SITE_LOCALE.replace("-", "_"),
|
||||
type: "website",
|
||||
},
|
||||
twitter: {
|
||||
creator: `@${config.authorSocial?.twitter}`,
|
||||
creator: `@${authorConfig.social?.twitter}`,
|
||||
},
|
||||
alternates: {
|
||||
canonical: "/",
|
||||
types: {
|
||||
"application/rss+xml": [
|
||||
{
|
||||
title: `${config.siteName} (RSS)`,
|
||||
title: `${siteConfig.name} (RSS)`,
|
||||
url: "/feed.xml",
|
||||
},
|
||||
],
|
||||
"application/atom+xml": [
|
||||
{
|
||||
title: `${config.siteName} (Atom)`,
|
||||
title: `${siteConfig.name} (Atom)`,
|
||||
url: "/feed.atom",
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { env } from "../../lib/env";
|
||||
import { env } from "@/lib/env";
|
||||
import { cache } from "react";
|
||||
import path from "path";
|
||||
import fs from "fs/promises";
|
||||
import glob from "fast-glob";
|
||||
import { unified } from "unified";
|
||||
import { remarkHtml, remarkParse, remarkSmartypants, remarkFrontmatter } from "./mdx/remark";
|
||||
import { remarkHtml, remarkParse, remarkSmartypants, remarkFrontmatter } from "@/lib/helpers/mdx/remark";
|
||||
import { decode } from "html-entities";
|
||||
import { POSTS_DIR } from "../config/constants";
|
||||
import { POSTS_DIR } from "@/lib/config/constants";
|
||||
|
||||
export type FrontMatter = {
|
||||
slug: string;
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import { Redis } from "@upstash/redis";
|
||||
|
||||
// pulls credentials (prefixed with 'KV_REST_API_') set automatically by Vercel marketplace integration:
|
||||
// https://github.com/upstash/redis-js/blob/091e0a0949593d74b905f41f7cb409ada16f936f/platforms/nodejs.ts#L184
|
||||
const redis = Redis.fromEnv();
|
||||
|
||||
export default redis;
|
||||
@@ -0,0 +1,6 @@
|
||||
import { clsx, type ClassValue } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
export const cn = (...inputs: ClassValue[]) => {
|
||||
return twMerge(clsx(inputs));
|
||||
};
|
||||
Reference in New Issue
Block a user