diff --git a/components/NoteMeta/NoteMeta.tsx b/components/NoteMeta/NoteMeta.tsx index 281ad445..6c48ee87 100644 --- a/components/NoteMeta/NoteMeta.tsx +++ b/components/NoteMeta/NoteMeta.tsx @@ -6,7 +6,7 @@ import NoteTitle from "../NoteTitle"; import { DateIcon, TagIcon, EditIcon, ViewsIcon } from "../Icons"; import { styled } from "../../lib/styles/stitches.config"; import * as config from "../../lib/config"; -import type { NoteType } from "../../types"; +import type { NoteFrontMatter } from "../../types"; const Wrapper = styled("div", { display: "inline-flex", @@ -56,7 +56,7 @@ const Tag = styled("span", { }, }); -export type NoteMetaProps = Pick; +export type NoteMetaProps = Pick; const NoteMeta = ({ slug, date, title, htmlTitle, tags = [] }: NoteMetaProps) => ( <> diff --git a/components/NoteTitle/NoteTitle.tsx b/components/NoteTitle/NoteTitle.tsx index 7ef33d7b..c2150797 100644 --- a/components/NoteTitle/NoteTitle.tsx +++ b/components/NoteTitle/NoteTitle.tsx @@ -1,7 +1,7 @@ import NextLink from "next/link"; import { styled } from "../../lib/styles/stitches.config"; import type { ComponentProps } from "react"; -import type { NoteType } from "../../types"; +import type { NoteFrontMatter } from "../../types"; const Title = styled("h1", { margin: "0.3em 0 0.5em -1px", // misaligned left margin, super nitpicky @@ -23,7 +23,7 @@ const Link = styled("a", { textDecoration: "none", }); -export type NoteTitleProps = Pick & ComponentProps; +export type NoteTitleProps = Pick & ComponentProps; const NoteTitle = ({ slug, htmlTitle, ...rest }: NoteTitleProps) => ( diff --git a/components/NotesList/NotesList.tsx b/components/NotesList/NotesList.tsx index 30ddad7f..8b5676ce 100644 --- a/components/NotesList/NotesList.tsx +++ b/components/NotesList/NotesList.tsx @@ -1,7 +1,7 @@ import Link from "../Link"; import Time from "../Time"; import { styled } from "../../lib/styles/stitches.config"; -import type { NoteType } from "../../types"; +import type { NoteFrontMatter } from "../../types"; const Section = styled("section", { fontSize: "1.1em", @@ -54,13 +54,13 @@ const PostDate = styled(Time, { }); export type NotesListProps = { - notesByYear: Record<string, NoteType["frontMatter"][]>; + notesByYear: Record<string, NoteFrontMatter[]>; }; const NotesList = ({ notesByYear }: NotesListProps) => { const sections = []; - Object.entries(notesByYear).forEach(([year, notes]: [string, NoteType["frontMatter"][]]) => { + Object.entries(notesByYear).forEach(([year, notes]: [string, NoteFrontMatter[]]) => { sections.push( <Section key={year}> <Year>{year}</Year> diff --git a/components/RepositoryCard/RepositoryCard.tsx b/components/RepositoryCard/RepositoryCard.tsx index 90129775..dfda6da8 100644 --- a/components/RepositoryCard/RepositoryCard.tsx +++ b/components/RepositoryCard/RepositoryCard.tsx @@ -3,7 +3,7 @@ import RelativeTime from "../RelativeTime"; import { StarOcticon, ForkOcticon } from "../Icons"; import { commafy } from "../../lib/helpers/format-number"; import { styled } from "../../lib/styles/stitches.config"; -import type { RepositoryType } from "../../types"; +import type { Repository } from "../../types"; const Wrapper = styled("div", { width: "100%", @@ -68,7 +68,7 @@ const LanguageCircle = styled("span", { verticalAlign: "text-top", }); -export type RepositoryCardProps = RepositoryType & { +export type RepositoryCardProps = Repository & { className?: string; }; diff --git a/lib/config/constants.ts b/lib/config/constants.ts index abd83e82..14fa4f72 100644 --- a/lib/config/constants.ts +++ b/lib/config/constants.ts @@ -1,4 +1,6 @@ // Next.js constants (not needed in frontend) + +// directory containing .mdx files relative to project root export const NOTES_DIR = "./notes"; // normalize the timestamp saved when building/deploying (see next.config.js) and fall back to right now: diff --git a/lib/helpers/parse-notes.ts b/lib/helpers/parse-notes.ts index e10bd840..943bcffb 100644 --- a/lib/helpers/parse-notes.ts +++ b/lib/helpers/parse-notes.ts @@ -19,20 +19,27 @@ import remarkGfm from "remark-gfm"; import rehypeSlug from "rehype-slug"; import rehypePrism from "rehype-prism-plus"; -import type { NoteType } from "../../types"; +import type { Note, NoteFrontMatter } from "../../types"; + +const ABSOLUTE_NOTES_DIR = path.join(process.cwd(), NOTES_DIR); // returns all .mdx files in NOTES_DIR (without .mdx extension) export const getNoteSlugs = async (): Promise<string[]> => { // get all files in NOTES_DIR - const files = await fs.readdir(path.join(process.cwd(), NOTES_DIR)); + const files = await fs.readdir(ABSOLUTE_NOTES_DIR); // narrow to only the .mdx files and strip the .mdx extension return files.filter((file) => /\.mdx$/.test(file)).map((noteFile) => noteFile.replace(/\.mdx$/, "")); }; // returns front matter and/or *raw* markdown contents of a given slug -export const getNoteData = async (slug: string): Promise<Omit<NoteType, "source"> & { content: string }> => { - const fullPath = path.join(process.cwd(), NOTES_DIR, `${slug}.mdx`); +export const getNoteData = async ( + slug: string +): Promise<{ + frontMatter: NoteFrontMatter; + content: string; +}> => { + const fullPath = path.join(ABSOLUTE_NOTES_DIR, `${slug}.mdx`); const rawContent = await fs.readFile(fullPath, "utf8"); const { data, content } = matter(rawContent); @@ -52,7 +59,7 @@ export const getNoteData = async (slug: string): Promise<Omit<NoteType, "source" // return both the parsed YAML front matter (with a few amendments) and the raw, unparsed markdown content return { frontMatter: { - ...(data as Omit<NoteType["frontMatter"], "slug" | "title" | "htmlTitle" | "permalink" | "date" | "readingMins">), + ...(data as Partial<NoteFrontMatter>), // zero markdown title: title: removeMarkdown(data.title), // parsed markdown title: @@ -67,7 +74,7 @@ export const getNoteData = async (slug: string): Promise<Omit<NoteType, "source" }; // fully parses MDX into JS and returns *everything* about a note -export const getNote = async (slug: string): Promise<NoteType> => { +export const getNote = async (slug: string): Promise<Note> => { const { frontMatter, content } = await getNoteData(slug); const source = await serialize(content, { parseFrontmatter: false, @@ -99,7 +106,7 @@ export const getNote = async (slug: string): Promise<NoteType> => { }; // returns the front matter of ALL notes, sorted reverse chronologically -export const getAllNotes = async (): Promise<NoteType["frontMatter"][]> => { +export const getAllNotes = async (): Promise<NoteFrontMatter[]> => { const slugs = await getNoteSlugs(); // for each slug, query its front matter @@ -108,9 +115,7 @@ export const getAllNotes = async (): Promise<NoteType["frontMatter"][]> => { }); // sort the results by date - const sorted = data.sort((note1: NoteType["frontMatter"], note2: NoteType["frontMatter"]) => - note1.date > note2.date ? -1 : 1 - ); + const sorted = data.sort((note1, note2) => (note1.date > note2.date ? -1 : 1)); return sorted; }; diff --git a/pages/notes/[slug].tsx b/pages/notes/[slug].tsx index d38ef5e0..be07741d 100644 --- a/pages/notes/[slug].tsx +++ b/pages/notes/[slug].tsx @@ -10,9 +10,9 @@ import { getNote, getNoteSlugs } from "../../lib/helpers/parse-notes"; import * as config from "../../lib/config"; import { articleJsonLd } from "../../lib/config/seo"; import type { GetStaticProps, GetStaticPaths } from "next"; -import type { NoteType } from "../../types"; +import type { Note, NoteFrontMatter } from "../../types"; -const Note = ({ frontMatter, source }: NoteType) => { +const Note = ({ frontMatter, source }: Note) => { return ( <> <NextSeo @@ -74,7 +74,7 @@ const Note = ({ frontMatter, source }: NoteType) => { ); }; -export const getStaticProps: GetStaticProps = async ({ params }: { params: Pick<NoteType["frontMatter"], "slug"> }) => { +export const getStaticProps: GetStaticProps = async ({ params }: { params: Pick<NoteFrontMatter, "slug"> }) => { const { frontMatter, source } = await getNote(params.slug); return { diff --git a/pages/projects.tsx b/pages/projects.tsx index af27fced..a9188d5f 100644 --- a/pages/projects.tsx +++ b/pages/projects.tsx @@ -8,7 +8,7 @@ import { OctocatOcticon } from "../components/Icons"; import { styled } from "../lib/styles/stitches.config"; import { authorSocial } from "../lib/config"; import type { GetStaticProps } from "next"; -import type { RepositoryType } from "../types"; +import type { Repository } from "../types"; const Wrapper = styled("div", { display: "flex", @@ -54,7 +54,7 @@ const Projects = ({ repos }) => ( <Content> <Wrapper> - {repos.map((repo: RepositoryType) => ( + {repos.map((repo: Repository) => ( <Card key={repo.name} {...repo} /> ))} </Wrapper> @@ -111,7 +111,7 @@ export const getStaticProps: GetStaticProps = async () => { } ); - const repos: RepositoryType[] = user.repositories.edges.map(({ node: repo }) => ({ + const repos: Repository[] = user.repositories.edges.map(({ node: repo }) => ({ name: repo.name, url: repo.url, description: repo.description, diff --git a/types/note.d.ts b/types/note.d.ts index 090a894b..6e9fe923 100644 --- a/types/note.d.ts +++ b/types/note.d.ts @@ -1,18 +1,21 @@ import type { MDXRemoteSerializeResult } from "next-mdx-remote"; -export type NoteType = { - frontMatter: { - slug: string; - permalink: string; - date: string; - title: string; - htmlTitle?: string; - description?: string; - image?: string; - tags?: string[]; - readingMins?: number; - noComments?: boolean; - }; +export type NoteFrontMatter = { + slug: string; + permalink: string; + date: string; + title: string; + htmlTitle?: string; + description?: string; + image?: string; + tags?: string[]; + readingMins?: number; + noComments?: boolean; +}; + +export type Note = { + // yaml metadata + frontMatter: NoteFrontMatter; // the final, compiled JSX by next-mdx-remote; see lib/helpers/parse-notes.ts source: MDXRemoteSerializeResult; diff --git a/types/repository.d.ts b/types/repository.d.ts index 03f8c86a..ca8d5ceb 100644 --- a/types/repository.d.ts +++ b/types/repository.d.ts @@ -1,4 +1,4 @@ -export type RepositoryType = { +export type Repository = { name: string; url: string; description?: string;