diff --git a/packages/www/next.config.js b/packages/www/next.config.js index e4d9086d..48279f46 100644 --- a/packages/www/next.config.js +++ b/packages/www/next.config.js @@ -1,5 +1,57 @@ // @ts-check +const fs = require("fs"); +const path = require("path"); + +function parseMarkdownTitle(/** @type {string} */ source) { + const firstLine = source.split("\n")[0]; + if (firstLine == null) { + throw new Error("No title."); + } + const START = 'export const title = "'; + if (!firstLine.startsWith(START) || !firstLine.endsWith('";')) { + throw new Error(`Invalid title line:\n${firstLine}`); + } + return firstLine.substring(START.length, firstLine.length - 2).trim(); +} + +function computeAllMedatada() { + const BLOG_POSTS_ROOT = path.join("src", "app", "blog", "(blog-posts)"); + + /** @type {import("./src/lib/metadata").BlogPostMetadata[]} */ + const allMetadata = []; + for (const year of fs.readdirSync(BLOG_POSTS_ROOT)) { + if (year === "layout.tsx") { + continue; + } + for (const month of fs.readdirSync(path.join(BLOG_POSTS_ROOT, year))) { + for (const date of fs.readdirSync(path.join(BLOG_POSTS_ROOT, year, month))) { + for (const titleSlug of fs.readdirSync(path.join(BLOG_POSTS_ROOT, year, month, date))) { + const fullPath = path.join(BLOG_POSTS_ROOT, year, month, date, titleSlug, "page.mdx"); + const content = fs.readFileSync(fullPath).toString(); + try { + const title = parseMarkdownTitle(content); + allMetadata.push({ title, year, month, date, titleSlug }); + } catch (error) { + throw new Error(`Failed to parse ${fullPath}, error: ${error}`); + } + } + } + } + } + + allMetadata.sort((a, b) => { + let c = b.year.localeCompare(a.year); + if (c !== 0) return c; + c = b.month.localeCompare(a.month); + if (c !== 0) return c; + c = b.date.localeCompare(a.date); + return c; + }); + + return allMetadata; +} + const withMDX = require("@next/mdx")({ extension: /\.mdx?$/, options: { @@ -10,8 +62,10 @@ const withMDX = require("@next/mdx")({ /** @type {import('next').NextConfig} */ const nextConfig = { + pageExtensions: ["tsx", "mdx"], experimental: { mdxRs: true }, output: "export", + env: { ALL_BLOG_POST_METADATA: JSON.stringify(computeAllMedatada()) }, typescript: { ignoreBuildErrors: true }, }; diff --git a/packages/www/package.json b/packages/www/package.json index 0c18e904..aecdc624 100644 --- a/packages/www/package.json +++ b/packages/www/package.json @@ -10,7 +10,7 @@ "dependencies": { "@mdx-js/loader": "^2.3.0", "@mdx-js/react": "2.0.0", - "@next/mdx": "^13.5.3", + "@next/mdx": "^13.5.4", "@types/mdx": "^2.0.8", "autoprefixer": "^10.4.16", "dev-sam-theme": "^0.0.1", diff --git a/packages/www/blog/1970-01-01-welcome-to-my-blog.mdx b/packages/www/src/app/blog/(blog-posts)/1970/01/01/welcome-to-my-blog/page.mdx similarity index 83% rename from packages/www/blog/1970-01-01-welcome-to-my-blog.mdx rename to packages/www/src/app/blog/(blog-posts)/1970/01/01/welcome-to-my-blog/page.mdx index b4867f66..06851bcc 100755 --- a/packages/www/blog/1970-01-01-welcome-to-my-blog.mdx +++ b/packages/www/src/app/blog/(blog-posts)/1970/01/01/welcome-to-my-blog/page.mdx @@ -1,4 +1,6 @@ export const title = "Welcome to My Blog!"; +import blogPostPageMetadata from '../../../../../../../lib/blog-post-page-metadata'; +export const metadata = blogPostPageMetadata(title); This is the zeroth post in my blog. Since the content of the post might change when I migrate the blog from one place to another, I choose to set the time to be `1970-01-01`. diff --git a/packages/www/blog/2016-12-30-nerd-pride.mdx b/packages/www/src/app/blog/(blog-posts)/2016/12/30/nerd-pride/page.mdx similarity index 99% rename from packages/www/blog/2016-12-30-nerd-pride.mdx rename to packages/www/src/app/blog/(blog-posts)/2016/12/30/nerd-pride/page.mdx index 9cf0e298..b80ff376 100644 --- a/packages/www/blog/2016-12-30-nerd-pride.mdx +++ b/packages/www/src/app/blog/(blog-posts)/2016/12/30/nerd-pride/page.mdx @@ -1,4 +1,6 @@ export const title = "Nerd Pride"; +import blogPostPageMetadata from '../../../../../../../lib/blog-post-page-metadata'; +export const metadata = blogPostPageMetadata(title); On the evening of December 8, 2016, exactly on 5:01 PM in Eastern Standard Time, the photons of Cornell Engineering acceptance letter struck my eyes. For me, it was a confirmation, a confirmation diff --git a/packages/www/blog/2017-05-31-project-defcon-1.mdx b/packages/www/src/app/blog/(blog-posts)/2017/05/31/project-defcon-1/page.mdx similarity index 95% rename from packages/www/blog/2017-05-31-project-defcon-1.mdx rename to packages/www/src/app/blog/(blog-posts)/2017/05/31/project-defcon-1/page.mdx index d776035f..1696dd44 100644 --- a/packages/www/blog/2017-05-31-project-defcon-1.mdx +++ b/packages/www/src/app/blog/(blog-posts)/2017/05/31/project-defcon-1/page.mdx @@ -1,4 +1,6 @@ export const title = "Project DEFCON 1: A Confidential Data Storage System"; +import blogPostPageMetadata from '../../../../../../../lib/blog-post-page-metadata'; +export const metadata = blogPostPageMetadata(title); ## 1.Introduction diff --git a/packages/www/blog/2018-06-15-sampl-alpha-design-choices.mdx b/packages/www/src/app/blog/(blog-posts)/2018/06/15/sampl-alpha-design-choices/page.mdx similarity index 98% rename from packages/www/blog/2018-06-15-sampl-alpha-design-choices.mdx rename to packages/www/src/app/blog/(blog-posts)/2018/06/15/sampl-alpha-design-choices/page.mdx index f3fec473..9cf481c8 100755 --- a/packages/www/blog/2018-06-15-sampl-alpha-design-choices.mdx +++ b/packages/www/src/app/blog/(blog-posts)/2018/06/15/sampl-alpha-design-choices/page.mdx @@ -1,4 +1,6 @@ export const title = "Design Choice of SAMPL - Written After the First Alpha Release"; +import blogPostPageMetadata from '../../../../../../../lib/blog-post-page-metadata'; +export const metadata = blogPostPageMetadata(title); ## Beginning diff --git a/packages/www/blog/2018-06-19-sampl-fun-ref-mistake-fix.mdx b/packages/www/src/app/blog/(blog-posts)/2018/06/19/sampl-fun-ref-mistake-fix/page.mdx similarity index 97% rename from packages/www/blog/2018-06-19-sampl-fun-ref-mistake-fix.mdx rename to packages/www/src/app/blog/(blog-posts)/2018/06/19/sampl-fun-ref-mistake-fix/page.mdx index 4ba5d743..d167c617 100755 --- a/packages/www/blog/2018-06-19-sampl-fun-ref-mistake-fix.mdx +++ b/packages/www/src/app/blog/(blog-posts)/2018/06/19/sampl-fun-ref-mistake-fix/page.mdx @@ -1,4 +1,6 @@ export const title = "Function Reference in SAMPL - A Design Mistake and the Fix"; +import blogPostPageMetadata from '../../../../../../../lib/blog-post-page-metadata'; +export const metadata = blogPostPageMetadata(title); ## Background diff --git a/packages/www/blog/2018-08-27-cw-turing-complete.mdx b/packages/www/src/app/blog/(blog-posts)/2018/08/27/cw-turing-complete/page.mdx similarity index 98% rename from packages/www/blog/2018-08-27-cw-turing-complete.mdx rename to packages/www/src/app/blog/(blog-posts)/2018/08/27/cw-turing-complete/page.mdx index eccfb941..e04e6b73 100755 --- a/packages/www/blog/2018-08-27-cw-turing-complete.mdx +++ b/packages/www/src/app/blog/(blog-posts)/2018/08/27/cw-turing-complete/page.mdx @@ -1,4 +1,6 @@ export const title = "Critter World is Turing Complete - A Not-So-Rigorous Proof"; +import blogPostPageMetadata from '../../../../../../../lib/blog-post-page-metadata'; +export const metadata = blogPostPageMetadata(title); Critter World is Cornell's CS 2112's Final Project. It is a simulated hexagon world where critters, controled by programs, can move, eat, mate, bud, attack, etc. The programming language is very diff --git a/packages/www/blog/2018-12-31-cs-in-high-schools.mdx b/packages/www/src/app/blog/(blog-posts)/2018/12/31/cs-in-high-schools/page.mdx similarity index 99% rename from packages/www/blog/2018-12-31-cs-in-high-schools.mdx rename to packages/www/src/app/blog/(blog-posts)/2018/12/31/cs-in-high-schools/page.mdx index c7974939..ffe5f6d0 100755 --- a/packages/www/blog/2018-12-31-cs-in-high-schools.mdx +++ b/packages/www/src/app/blog/(blog-posts)/2018/12/31/cs-in-high-schools/page.mdx @@ -1,4 +1,6 @@ export const title = "Computer Science in High Schools"; +import blogPostPageMetadata from '../../../../../../../lib/blog-post-page-metadata'; +export const metadata = blogPostPageMetadata(title); This year, I got an intern with a resume that did not mention my high school's CS project with a single word. Therefore, at this point, either success or failure in my high school CS career does diff --git a/packages/www/blog/2019-01-12-samlang-alpha-design-choices.mdx b/packages/www/src/app/blog/(blog-posts)/2019/01/12/samlang-alpha-design-choices/page.mdx similarity index 98% rename from packages/www/blog/2019-01-12-samlang-alpha-design-choices.mdx rename to packages/www/src/app/blog/(blog-posts)/2019/01/12/samlang-alpha-design-choices/page.mdx index da2fe489..2cb08303 100755 --- a/packages/www/blog/2019-01-12-samlang-alpha-design-choices.mdx +++ b/packages/www/src/app/blog/(blog-posts)/2019/01/12/samlang-alpha-design-choices/page.mdx @@ -1,4 +1,6 @@ export const title = "Design Choice of samlang in Alpha"; +import blogPostPageMetadata from '../../../../../../../lib/blog-post-page-metadata'; +export const metadata = blogPostPageMetadata(title); ## Background diff --git a/packages/www/blog/2020-01-07-my-decade-in-review.mdx b/packages/www/src/app/blog/(blog-posts)/2020/01/07/my-decade-in-review/page.mdx similarity index 99% rename from packages/www/blog/2020-01-07-my-decade-in-review.mdx rename to packages/www/src/app/blog/(blog-posts)/2020/01/07/my-decade-in-review/page.mdx index 34002ea5..b1805935 100644 --- a/packages/www/blog/2020-01-07-my-decade-in-review.mdx +++ b/packages/www/src/app/blog/(blog-posts)/2020/01/07/my-decade-in-review/page.mdx @@ -1,4 +1,6 @@ export const title = "My Decade in Review"; +import blogPostPageMetadata from '../../../../../../../lib/blog-post-page-metadata'; +export const metadata = blogPostPageMetadata(title); Following the lead of React and JavaScript god [Dan Abramov](https://overreacted.io/), I decided to also publish my decade in review blog post. diff --git a/packages/www/blog/2020-01-09-implement-autocomplete.mdx b/packages/www/src/app/blog/(blog-posts)/2020/01/09/implement-autocomplete/page.mdx similarity index 99% rename from packages/www/blog/2020-01-09-implement-autocomplete.mdx rename to packages/www/src/app/blog/(blog-posts)/2020/01/09/implement-autocomplete/page.mdx index c0a79157..fa40943b 100644 --- a/packages/www/blog/2020-01-09-implement-autocomplete.mdx +++ b/packages/www/src/app/blog/(blog-posts)/2020/01/09/implement-autocomplete/page.mdx @@ -1,4 +1,6 @@ export const title = "How to Implement Autocomplete"; +import blogPostPageMetadata from '../../../../../../../lib/blog-post-page-metadata'; +export const metadata = blogPostPageMetadata(title); Implement autocomplete in 79 lines of code. Actually, it's not that easy. diff --git a/packages/www/blog/2020-05-14-one-year-as-dev-lead.mdx b/packages/www/src/app/blog/(blog-posts)/2020/05/14/one-year-as-dev-lead/page.mdx similarity index 98% rename from packages/www/blog/2020-05-14-one-year-as-dev-lead.mdx rename to packages/www/src/app/blog/(blog-posts)/2020/05/14/one-year-as-dev-lead/page.mdx index 976612b3..4900362f 100644 --- a/packages/www/blog/2020-05-14-one-year-as-dev-lead.mdx +++ b/packages/www/src/app/blog/(blog-posts)/2020/05/14/one-year-as-dev-lead/page.mdx @@ -1,4 +1,6 @@ export const title = "One Year as Developer Lead"; +import blogPostPageMetadata from '../../../../../../../lib/blog-post-page-metadata'; +export const metadata = blogPostPageMetadata(title); Almost a year ago, I started to perform developer lead responsibilities at [Cornell DTI](https://www.cornelldti.org). My first major task was to grade part of developers at diff --git a/packages/www/blog/2020-05-17-samlang-in-browser.mdx b/packages/www/src/app/blog/(blog-posts)/2020/05/17/samlang-in-browser/page.mdx similarity index 99% rename from packages/www/blog/2020-05-17-samlang-in-browser.mdx rename to packages/www/src/app/blog/(blog-posts)/2020/05/17/samlang-in-browser/page.mdx index 3ad92ff8..8b91ed6d 100644 --- a/packages/www/blog/2020-05-17-samlang-in-browser.mdx +++ b/packages/www/src/app/blog/(blog-posts)/2020/05/17/samlang-in-browser/page.mdx @@ -1,4 +1,6 @@ export const title = "Making samlang Run in Browsers"; +import blogPostPageMetadata from '../../../../../../../lib/blog-post-page-metadata'; +export const metadata = blogPostPageMetadata(title); ## Background diff --git a/packages/www/blog/2020-08-30-samlang-ts-rewrite.mdx b/packages/www/src/app/blog/(blog-posts)/2020/08/30/samlang-ts-rewrite/page.mdx similarity index 98% rename from packages/www/blog/2020-08-30-samlang-ts-rewrite.mdx rename to packages/www/src/app/blog/(blog-posts)/2020/08/30/samlang-ts-rewrite/page.mdx index 0384e8d7..766ed7de 100644 --- a/packages/www/blog/2020-08-30-samlang-ts-rewrite.mdx +++ b/packages/www/src/app/blog/(blog-posts)/2020/08/30/samlang-ts-rewrite/page.mdx @@ -1,4 +1,6 @@ export const title = "Rewriting samlang in TypeScript"; +import blogPostPageMetadata from '../../../../../../../lib/blog-post-page-metadata'; +export const metadata = blogPostPageMetadata(title); A lot has changed since my [last blog post](/blog/2020/05/17/samlang-in-browser) on my effort to make samlang run in browsers. The samlang demo site has been merged into the samlang documentation site diff --git a/packages/www/blog/2021-01-24-samlang-llvm-backend.mdx b/packages/www/src/app/blog/(blog-posts)/2021/01/24/samlang-llvm-backend/page.mdx similarity index 99% rename from packages/www/blog/2021-01-24-samlang-llvm-backend.mdx rename to packages/www/src/app/blog/(blog-posts)/2021/01/24/samlang-llvm-backend/page.mdx index 4ee401be..d76f57d8 100644 --- a/packages/www/blog/2021-01-24-samlang-llvm-backend.mdx +++ b/packages/www/src/app/blog/(blog-posts)/2021/01/24/samlang-llvm-backend/page.mdx @@ -1,4 +1,6 @@ export const title = "Supporting the LLVM Backend for samlang"; +import blogPostPageMetadata from '../../../../../../../lib/blog-post-page-metadata'; +export const metadata = blogPostPageMetadata(title); LLVM is a collection of compiler toolchain that allows you to target any instruction set from any source-level programming language. Once the source code has been lowered to LLVM IR, the LLVM diff --git a/packages/www/blog/2021-02-16-squash-and-merge.mdx b/packages/www/src/app/blog/(blog-posts)/2021/02/16/squash-and-merge/page.mdx similarity index 98% rename from packages/www/blog/2021-02-16-squash-and-merge.mdx rename to packages/www/src/app/blog/(blog-posts)/2021/02/16/squash-and-merge/page.mdx index ed08919f..ffd15a6f 100644 --- a/packages/www/blog/2021-02-16-squash-and-merge.mdx +++ b/packages/www/src/app/blog/(blog-posts)/2021/02/16/squash-and-merge/page.mdx @@ -1,4 +1,6 @@ export const title = "The Case for Squash and Merge"; +import blogPostPageMetadata from '../../../../../../../lib/blog-post-page-metadata'; +export const metadata = blogPostPageMetadata(title); There are several things I have very passionate opinions on, like whether opening braces `{` should be on a new line, etc. _(Answer: NO NO NO!)_ Merging in a pull request using squash and merge is diff --git a/packages/www/blog/2021-10-29-samlang-wasm-backend.mdx b/packages/www/src/app/blog/(blog-posts)/2021/10/29/samlang-wasm-backend/page.mdx similarity index 98% rename from packages/www/blog/2021-10-29-samlang-wasm-backend.mdx rename to packages/www/src/app/blog/(blog-posts)/2021/10/29/samlang-wasm-backend/page.mdx index 7544df4c..976f2cb4 100644 --- a/packages/www/blog/2021-10-29-samlang-wasm-backend.mdx +++ b/packages/www/src/app/blog/(blog-posts)/2021/10/29/samlang-wasm-backend/page.mdx @@ -1,5 +1,6 @@ export const title = "WebAssembly Backend for samlang"; -export const ogImage = "/blog/2021-10-29-samlang-wasm-backend/wasm.png"; +import blogPostPageMetadata from '../../../../../../../lib/blog-post-page-metadata'; +export const metadata = blogPostPageMetadata(title, "/blog/2021-10-29-samlang-wasm-backend/wasm.png"); Since the release of Apple M1 MacBook, a ticking bomb starts: eventually there will be a day that I cannot run the compiled samlang code anymore, if samlang compiler does not change. samlang must diff --git a/packages/www/blog/2022-01-02-courseplan-review.mdx b/packages/www/src/app/blog/(blog-posts)/2022/01/02/courseplan-review/page.mdx similarity index 98% rename from packages/www/blog/2022-01-02-courseplan-review.mdx rename to packages/www/src/app/blog/(blog-posts)/2022/01/02/courseplan-review/page.mdx index 8672e32b..9dc9cc90 100644 --- a/packages/www/blog/2022-01-02-courseplan-review.mdx +++ b/packages/www/src/app/blog/(blog-posts)/2022/01/02/courseplan-review/page.mdx @@ -1,5 +1,6 @@ export const title = "CoursePlan: A Unique Design & Tech Initiative"; -export const ogImage = "/blog/2022-01-02-courseplan-review/two-graphs-theory.png"; +import blogPostPageMetadata from '../../../../../../../lib/blog-post-page-metadata'; +export const metadata = blogPostPageMetadata(title, "/blog/2022-01-02-courseplan-review/two-graphs-theory.png"); ## Introduction diff --git a/packages/www/blog/2022-01-28-why-useless-code.mdx b/packages/www/src/app/blog/(blog-posts)/2022/01/28/why-useless-code/page.mdx similarity index 95% rename from packages/www/blog/2022-01-28-why-useless-code.mdx rename to packages/www/src/app/blog/(blog-posts)/2022/01/28/why-useless-code/page.mdx index 59c087a4..19d0d3d5 100644 --- a/packages/www/blog/2022-01-28-why-useless-code.mdx +++ b/packages/www/src/app/blog/(blog-posts)/2022/01/28/why-useless-code/page.mdx @@ -1,4 +1,6 @@ export const title = "Why I Write Useless Code"; +import blogPostPageMetadata from '../../../../../../../lib/blog-post-page-metadata'; +export const metadata = blogPostPageMetadata(title); There are a lot of ways you can categorize code, but in this blog post, I will mostly focus on their usefulness. Some code can be useful, or designed to be useful but actually useless. You might diff --git a/packages/www/blog/2022-09-05-bounded-qualification.mdx b/packages/www/src/app/blog/(blog-posts)/2022/09/05/bounded-qualification/page.mdx similarity index 98% rename from packages/www/blog/2022-09-05-bounded-qualification.mdx rename to packages/www/src/app/blog/(blog-posts)/2022/09/05/bounded-qualification/page.mdx index 0947c7c4..a34d2337 100644 --- a/packages/www/blog/2022-09-05-bounded-qualification.mdx +++ b/packages/www/src/app/blog/(blog-posts)/2022/09/05/bounded-qualification/page.mdx @@ -1,5 +1,6 @@ export const title = "Bounded Qualification in samlang"; -export const ogImage = "/blog/2022-09-05-bounded-qualification/bounded-qualification.png"; +import blogPostPageMetadata from '../../../../../../../lib/blog-post-page-metadata'; +export const metadata = blogPostPageMetadata(title, "/blog/2022-09-05-bounded-qualification/bounded-qualification.png"); ## Introduction diff --git a/packages/www/blog/2023-01-08-samlang-rust-rewrite.mdx b/packages/www/src/app/blog/(blog-posts)/2023/01/08/samlang-rust-rewrite/page.mdx similarity index 97% rename from packages/www/blog/2023-01-08-samlang-rust-rewrite.mdx rename to packages/www/src/app/blog/(blog-posts)/2023/01/08/samlang-rust-rewrite/page.mdx index aee0e927..994909b4 100644 --- a/packages/www/blog/2023-01-08-samlang-rust-rewrite.mdx +++ b/packages/www/src/app/blog/(blog-posts)/2023/01/08/samlang-rust-rewrite/page.mdx @@ -1,5 +1,6 @@ export const title = "Rewriting samlang in Rust"; -export const ogImage = "/blog/2023-01-08-samlang-in-rust/optimization.png"; +import blogPostPageMetadata from '../../../../../../../lib/blog-post-page-metadata'; +export const metadata = blogPostPageMetadata(title, "/blog/2023-01-08-samlang-in-rust/optimization.png"); ## Motivation diff --git a/packages/www/blog/2023-09-11-life-of-high-school-cs-club-member.mdx b/packages/www/src/app/blog/(blog-posts)/2023/09/11/life-of-high-school-cs-club-member/page.mdx similarity index 98% rename from packages/www/blog/2023-09-11-life-of-high-school-cs-club-member.mdx rename to packages/www/src/app/blog/(blog-posts)/2023/09/11/life-of-high-school-cs-club-member/page.mdx index 150efd0a..1702d22c 100644 --- a/packages/www/blog/2023-09-11-life-of-high-school-cs-club-member.mdx +++ b/packages/www/src/app/blog/(blog-posts)/2023/09/11/life-of-high-school-cs-club-member/page.mdx @@ -1,4 +1,6 @@ export const title = "Life of a High School CS Club President, from a SWE's Perspective"; +import blogPostPageMetadata from '../../../../../../../lib/blog-post-page-metadata'; +export const metadata = blogPostPageMetadata(title); Imagine yourself being the president of the [CS club at my high school](https://computerization.io). You are now in grade 11 and have just taken over the presidency from the seniors. You have grand diff --git a/packages/www/blog/2023-09-23-samlang-perf-opt.mdx b/packages/www/src/app/blog/(blog-posts)/2023/09/23/samlang-perf-opt/page.mdx similarity index 97% rename from packages/www/blog/2023-09-23-samlang-perf-opt.mdx rename to packages/www/src/app/blog/(blog-posts)/2023/09/23/samlang-perf-opt/page.mdx index c2ca4737..3dd19d4a 100644 --- a/packages/www/blog/2023-09-23-samlang-perf-opt.mdx +++ b/packages/www/src/app/blog/(blog-posts)/2023/09/23/samlang-perf-opt/page.mdx @@ -1,5 +1,6 @@ export const title = "Performance Optimization on the samlang Compiler"; -export const ogImage = "/blog/2023-09-23-samlang-perf-opt/comparison.png"; +import blogPostPageMetadata from '../../../../../../../lib/blog-post-page-metadata'; +export const metadata = blogPostPageMetadata(title, "/blog/2023-09-23-samlang-perf-opt/comparison.png"); With a long-planned Rust rewrite of samlang finally done at the start of 2023, I decided to focus this year on fixing a lot of rough edges of the language, including syntax, semantics, and IDE services. Nine months later, I managed to tick quite a few items in the continuously growing [checklist](https://github.com/SamChou19815/samlang/issues/921). diff --git a/packages/www/blog/2023-10-01-what-happens-if-react-is-eager.mdx b/packages/www/src/app/blog/(blog-posts)/2023/10/01/what-happens-if-react-is-eager/page.mdx similarity index 98% rename from packages/www/blog/2023-10-01-what-happens-if-react-is-eager.mdx rename to packages/www/src/app/blog/(blog-posts)/2023/10/01/what-happens-if-react-is-eager/page.mdx index a8c32538..6f8fbcf8 100644 --- a/packages/www/blog/2023-10-01-what-happens-if-react-is-eager.mdx +++ b/packages/www/src/app/blog/(blog-posts)/2023/10/01/what-happens-if-react-is-eager/page.mdx @@ -1,4 +1,6 @@ export const title = "What Will Happen if React Evaluates JSX Eagerly?"; +import blogPostPageMetadata from '../../../../../../../lib/blog-post-page-metadata'; +export const metadata = blogPostPageMetadata(title); TLDR: Absolute Chaos diff --git a/packages/www/src/app/blog/(blog-posts)/layout.tsx b/packages/www/src/app/blog/(blog-posts)/layout.tsx new file mode 100644 index 00000000..53abc018 --- /dev/null +++ b/packages/www/src/app/blog/(blog-posts)/layout.tsx @@ -0,0 +1,14 @@ +import BlogDocumentWrapper from "../../../lib/BlogDocumentWrapper"; +import BlogPostItemContextAware from "../../../lib/BlogPostItemContextAware"; + +export default function BlogPostPageLayout({ children }: { children: React.ReactNode }) { + return ( + +
+
+ {children} +
+
+
+ ); +} diff --git a/packages/www/src/app/blog/[year]/[month]/[date]/[titleSlug]/layout.tsx b/packages/www/src/app/blog/[year]/[month]/[date]/[titleSlug]/layout.tsx deleted file mode 100644 index 9e00293a..00000000 --- a/packages/www/src/app/blog/[year]/[month]/[date]/[titleSlug]/layout.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import BlogDocumentWrapper from "../../../../../../lib/BlogDocumentWrapper"; -import BlogPostItem from "../../../../../../lib/BlogPostItem"; -import BlogPostPaginator from "../../../../../../lib/BlogPostPaginator"; -import allMetadata from "../../../../../../lib/metadata"; -import type { BlogPostPageParams } from "./page"; - -export default function BlogPostPageLayout({ - children, - params, -}: { children: React.ReactNode; params: BlogPostPageParams }) { - const permalink = `/blog/${params.year}/${params.month}/${params.date}/${params.titleSlug}`; - const metadata = allMetadata.find((it) => it.permalink === permalink); - if (metadata == null) { - throw permalink; - } - - return ( - -
-
- - {children} - -
- -
-
-
-
- ); -} diff --git a/packages/www/src/app/blog/[year]/[month]/[date]/[titleSlug]/page.tsx b/packages/www/src/app/blog/[year]/[month]/[date]/[titleSlug]/page.tsx deleted file mode 100644 index e4fddf2c..00000000 --- a/packages/www/src/app/blog/[year]/[month]/[date]/[titleSlug]/page.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import type { Metadata, ResolvingMetadata } from "next"; -import React from "react"; -import { BLOG_TITLE } from "../../../../../../lib/blog-constants.mjs"; -import Components from "../../../../../../lib/blog-post-mdx-components"; -import allMetadata from "../../../../../../lib/metadata"; - -export type BlogPostPageParams = { - readonly year: string; - readonly month: string; - readonly date: string; - readonly titleSlug: string; -}; - -export async function generateStaticParams(): Promise { - return allMetadata.map(({ year, month, date, titleSlug }) => ({ - year, - month, - date, - titleSlug, - })); -} - -export async function generateMetadata( - { params }: { readonly params: BlogPostPageParams }, - _parent: ResolvingMetadata, -): Promise { - const OG_IMAGE = "ogImage"; - const permalink = `/blog/${params.year}/${params.month}/${params.date}/${params.titleSlug}`; - const componentThunk = Components[permalink]; - if (componentThunk == null) throw permalink; - const Component = await componentThunk(); - - return { - title: `${Component.title} | ${BLOG_TITLE}`, - openGraph: { - type: "article", - title: `${Component.title} | ${BLOG_TITLE}`, - images: Component[OG_IMAGE], - }, - }; -} - -export default async function BlogPostPage({ - params, -}: { readonly params: BlogPostPageParams }): Promise { - const permalink = `/blog/${params.year}/${params.month}/${params.date}/${params.titleSlug}`; - const componentThunk = Components[permalink]; - if (componentThunk == null) throw permalink; - const { default: BlogPostContents } = await componentThunk(); - return ; -} diff --git a/packages/www/src/app/blog/page.tsx b/packages/www/src/app/blog/page.tsx index cb7a3d5a..546f3ff8 100644 --- a/packages/www/src/app/blog/page.tsx +++ b/packages/www/src/app/blog/page.tsx @@ -1,8 +1,9 @@ import type { Metadata } from "next"; +import Link from "next/link"; import BlogDocumentWrapper from "../../lib/BlogDocumentWrapper"; import BlogPostItem from "../../lib/BlogPostItem"; -import { BLOG_TITLE } from "../../lib/blog-constants.mjs"; -import allMetadata from "../../lib/metadata"; +import { BLOG_TITLE } from "../../lib/blog-constants"; +import { allMetadata, permalinkFromMetadata } from "../../lib/metadata"; export const metadata: Metadata = { title: BLOG_TITLE, @@ -21,9 +22,16 @@ export default async function BlogListPage(): Promise {
- {allMetadata.map((metadata) => ( - - ))} + {allMetadata.map((metadata) => { + const permalink = permalinkFromMetadata(metadata); + return ( + {metadata.title}} + formattedDate={`${metadata.year}-${metadata.month}-${metadata.date}`} + /> + ); + })}
diff --git a/packages/www/src/lib/BlogDocumentWrapper.tsx b/packages/www/src/lib/BlogDocumentWrapper.tsx index 86fb2509..65e2e1fd 100644 --- a/packages/www/src/lib/BlogDocumentWrapper.tsx +++ b/packages/www/src/lib/BlogDocumentWrapper.tsx @@ -1,6 +1,6 @@ import type { ReactNode } from "react"; import NavBar from "./NavBar"; -import { BLOG_TITLE } from "./blog-constants.mjs"; +import { BLOG_TITLE } from "./blog-constants"; export default function BlogDocumentWrapper({ children }: { children: ReactNode }): JSX.Element { return ( diff --git a/packages/www/src/lib/BlogPostItem.tsx b/packages/www/src/lib/BlogPostItem.tsx index 22c955a8..56a3f2cc 100644 --- a/packages/www/src/lib/BlogPostItem.tsx +++ b/packages/www/src/lib/BlogPostItem.tsx @@ -1,26 +1,21 @@ -import Link from "next/link"; - -type Props = { - readonly metadata: BlogPostMetadata; - readonly truncated?: boolean; - readonly children?: React.ReactNode; -}; - -export default function BlogPostItem(props: Props): JSX.Element { - const { children, metadata, truncated } = props; - const { title, formattedDate, permalink } = metadata; - - const TitleHeading = truncated ? "h2" : "h1"; +export default function BlogPostItem({ + title, + formattedDate, + children, +}: { + title: JSX.Element | string; + formattedDate: string; + children?: React.ReactNode; +}): JSX.Element { + const TitleHeading = typeof title === "string" ? "h1" : "h2"; return (
- - {truncated ? {title} : title} - + {title}
{formattedDate}
- {children &&
{children}
} + {children}
); } diff --git a/packages/www/src/lib/BlogPostItemContextAware.tsx b/packages/www/src/lib/BlogPostItemContextAware.tsx new file mode 100644 index 00000000..c664d32f --- /dev/null +++ b/packages/www/src/lib/BlogPostItemContextAware.tsx @@ -0,0 +1,72 @@ +"use client"; + +import Link from "next/link"; +import { usePathname } from "next/navigation"; +import BlogPostItem from "./BlogPostItem"; +import { allMetadata, permalinkFromMetadata } from "./metadata"; + +function PaginationNavItem({ + permalink, + title, + isLeft, +}: { + permalink: string; + title: string; + isLeft: boolean; +}): JSX.Element { + return ( + +
+ {isLeft ? "Newer Post" : "Older Post"} +
+
{isLeft ? `« ${title}` : `${title} »`}
+ + ); +} + +export default function BlogPostItemContextAware({ children }: { children: React.ReactNode }) { + const currentPath = usePathname(); + const index = allMetadata.findIndex((it) => currentPath.startsWith(permalinkFromMetadata(it))); + const metadata = allMetadata[index]; + if (metadata == null) throw currentPath; + const prevMetadata = allMetadata[index - 1]; + const nextMetadata = allMetadata[index + 1]; + + return ( +
+
+ +
{children}
+
+
+ +
+
+
+ ); +} diff --git a/packages/www/src/lib/BlogPostPaginator.tsx b/packages/www/src/lib/BlogPostPaginator.tsx deleted file mode 100644 index 40bb7c34..00000000 --- a/packages/www/src/lib/BlogPostPaginator.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import Link from "next/link"; -import allMetadata from "./metadata"; - -type PaginationNavItemProps = { - readonly permalink: string; - readonly isLeft: boolean; -}; - -function PaginationNavItem({ permalink, isLeft }: PaginationNavItemProps): JSX.Element { - const metadata = allMetadata.find((it) => it.permalink === permalink); - if (metadata == null) { - throw permalink; - } - - return ( - -
- {isLeft ? "Newer Post" : "Older Post"} -
-
- {isLeft ? `« ${metadata.title}` : `${metadata.title} »`} -
- - ); -} - -type Props = { - readonly nextPermalink?: string; - readonly prevPermalink?: string; -}; -export default function BlogPostPaginator({ nextPermalink, prevPermalink }: Props): JSX.Element { - return ( - - ); -} diff --git a/packages/www/src/lib/NavBar.tsx b/packages/www/src/lib/NavBar.tsx index 2fd4a42d..a8ae3826 100644 --- a/packages/www/src/lib/NavBar.tsx +++ b/packages/www/src/lib/NavBar.tsx @@ -1,15 +1,14 @@ import Link from "next/link"; -type Props = { - readonly title: string; - readonly titleLink: string; - readonly navItems: readonly { - readonly name: string; - readonly link: string; - }[]; -}; - -export default function NavBar({ title, titleLink, navItems }: Props): JSX.Element { +export default function NavBar({ + title, + titleLink, + navItems, +}: { + title: string; + titleLink: string; + navItems: ReadonlyArray<{ readonly name: string; readonly link: string }>; +}): JSX.Element { return (