From 8f9757936e754bfd341acbbb379f78c4d252c668 Mon Sep 17 00:00:00 2001 From: "Jip J. Dekker" Date: Wed, 29 Nov 2023 21:20:24 +1100 Subject: [PATCH] Update website to use typescript --- .build.yml | 3 +- .env.example | 1 + .gitignore | 6 +- README.md | 6 + jsconfig.json | 8 - mdx-components.tsx | 7 + next-env.d.ts | 5 + next.config.mjs | 8 +- package-lock.json | 763 ++++++++++++++++-- package.json | 16 +- postcss.config.js | 3 - prettier.config.js | 3 +- src/app/about/page.tsx | 161 ++++ .../page.mdx} | 9 +- .../2022-08-homebrew-minizinc/page.mdx} | 9 +- src/app/articles/page.tsx | 60 ++ {public => src/app}/favicon.ico | Bin src/app/feed.xml/route.ts | 62 ++ src/app/layout.tsx | 38 + src/app/not-found.tsx | 23 + src/{pages/index.jsx => app/page.tsx} | 136 ++-- src/app/projects/page.tsx | 93 +++ src/app/providers.tsx | 30 + src/app/speaking/page.tsx | 98 +++ src/app/uses/page.tsx | 123 +++ src/components/ArticleLayout.jsx | 60 -- src/components/ArticleLayout.tsx | 58 ++ src/components/{Button.jsx => Button.tsx} | 19 +- src/components/{Card.jsx => Card.tsx} | 45 +- src/components/Container.jsx | 42 - src/components/Container.tsx | 39 + src/components/{Footer.jsx => Footer.tsx} | 22 +- src/components/{Header.jsx => Header.tsx} | 99 ++- src/components/Layout.tsx | 19 + src/components/Prose.jsx | 7 - src/components/Prose.tsx | 10 + src/components/{SVGIcons.jsx => SVGIcons.tsx} | 50 +- src/components/{Section.jsx => Section.tsx} | 8 +- .../{SimpleLayout.jsx => SimpleLayout.tsx} | 12 +- .../{ThemeSelector.jsx => ThemeSelector.tsx} | 72 +- src/lib/articles.ts | 36 + src/lib/{formatDate.js => formatDate.ts} | 2 +- src/lib/generateRssFeed.js | 57 -- src/lib/getAllArticles.js | 23 - src/pages/_app.jsx | 38 - src/pages/_document.jsx | 63 -- src/pages/about.jsx | 155 ---- src/pages/articles/index.jsx | 69 -- src/pages/projects.jsx | 94 --- src/pages/speaking.jsx | 86 -- src/pages/uses.jsx | 119 --- tailwind.config.js | 306 ------- tailwind.config.ts | 28 + tsconfig.json | 28 + typography.ts | 283 +++++++ 55 files changed, 2203 insertions(+), 1417 deletions(-) create mode 100644 .env.example delete mode 100644 jsconfig.json create mode 100644 mdx-components.tsx create mode 100644 next-env.d.ts create mode 100644 src/app/about/page.tsx rename src/{pages/articles/2017-02-custom-dtrace-instrumentation.mdx => app/articles/2017-02-custom-dtrace-instrumentation/page.mdx} (97%) rename src/{pages/articles/2022-08-homebrew-minizinc.mdx => app/articles/2022-08-homebrew-minizinc/page.mdx} (94%) create mode 100644 src/app/articles/page.tsx rename {public => src/app}/favicon.ico (100%) create mode 100644 src/app/feed.xml/route.ts create mode 100644 src/app/layout.tsx create mode 100644 src/app/not-found.tsx rename src/{pages/index.jsx => app/page.tsx} (65%) create mode 100644 src/app/projects/page.tsx create mode 100644 src/app/providers.tsx create mode 100644 src/app/speaking/page.tsx create mode 100644 src/app/uses/page.tsx delete mode 100644 src/components/ArticleLayout.jsx create mode 100644 src/components/ArticleLayout.tsx rename src/components/{Button.jsx => Button.tsx} (68%) rename src/components/{Card.jsx => Card.tsx} (64%) delete mode 100644 src/components/Container.jsx create mode 100644 src/components/Container.tsx rename src/components/{Footer.jsx => Footer.tsx} (76%) rename src/components/{Header.jsx => Header.tsx} (82%) create mode 100644 src/components/Layout.tsx delete mode 100644 src/components/Prose.jsx create mode 100644 src/components/Prose.tsx rename src/components/{SVGIcons.jsx => SVGIcons.tsx} (88%) rename src/components/{Section.jsx => Section.tsx} (83%) rename src/components/{SimpleLayout.jsx => SimpleLayout.tsx} (67%) rename src/components/{ThemeSelector.jsx => ThemeSelector.tsx} (50%) create mode 100644 src/lib/articles.ts rename src/lib/{formatDate.js => formatDate.ts} (76%) delete mode 100644 src/lib/generateRssFeed.js delete mode 100644 src/lib/getAllArticles.js delete mode 100644 src/pages/_app.jsx delete mode 100644 src/pages/_document.jsx delete mode 100644 src/pages/about.jsx delete mode 100644 src/pages/articles/index.jsx delete mode 100644 src/pages/projects.jsx delete mode 100644 src/pages/speaking.jsx delete mode 100644 src/pages/uses.jsx delete mode 100644 tailwind.config.js create mode 100644 tailwind.config.ts create mode 100644 tsconfig.json create mode 100644 typography.ts diff --git a/.build.yml b/.build.yml index a832f0a..f19f189 100644 --- a/.build.yml +++ b/.build.yml @@ -3,7 +3,8 @@ packages: - npm oauth: pages.sr.ht/PAGES:RW environment: - site: dekker.one + site: "dekker.one" + NEXT_PUBLIC_SITE_URL: "https://dekker.one" tasks: - package: | cd $site diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..349d712 --- /dev/null +++ b/.env.example @@ -0,0 +1 @@ +NEXT_PUBLIC_SITE_URL=https://example.com diff --git a/.gitignore b/.gitignore index 016de9f..8f322f0 100644 --- a/.gitignore +++ b/.gitignore @@ -23,7 +23,6 @@ npm-debug.log* yarn-debug.log* yarn-error.log* -.pnpm-debug.log* # local env files .env*.local @@ -31,5 +30,6 @@ yarn-error.log* # vercel .vercel -# generated files -/public/rss/ +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/README.md b/README.md index 187d669..52562e3 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,12 @@ To get started with this template, first install the npm dependencies: npm install ``` +Next, create a `.env.local` file in the root of your project and set the `NEXT_PUBLIC_SITE_URL` variable to your site's public URL: + +``` +NEXT_PUBLIC_SITE_URL=https://example.com +``` + Next, run the development server: ```bash diff --git a/jsconfig.json b/jsconfig.json deleted file mode 100644 index 2c8ee2b..0000000 --- a/jsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "compilerOptions": { - "baseUrl": ".", - "paths": { - "@/*": ["src/*"] - } - } -} diff --git a/mdx-components.tsx b/mdx-components.tsx new file mode 100644 index 0000000..f52334c --- /dev/null +++ b/mdx-components.tsx @@ -0,0 +1,7 @@ +import { type MDXComponents } from 'mdx/types' + +export function useMDXComponents(components: MDXComponents) { + return { + ...components, + } +} diff --git a/next-env.d.ts b/next-env.d.ts new file mode 100644 index 0000000..4f11a03 --- /dev/null +++ b/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/next.config.mjs b/next.config.mjs index dcc2908..9e04760 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,14 +1,10 @@ +import rehypePrism from '@mapbox/rehype-prism' import nextMDX from '@next/mdx' import remarkGfm from 'remark-gfm' -import rehypePrism from '@mapbox/rehype-prism' /** @type {import('next').NextConfig} */ const nextConfig = { - pageExtensions: ['js', 'jsx', 'mdx'], - reactStrictMode: true, - experimental: { - scrollRestoration: true, - }, + pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'mdx'], output: 'export', images: { unoptimized: true, diff --git a/package-lock.json b/package-lock.json index b63edd3..eb5d53f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,25 +14,29 @@ "@mdx-js/react": "^3.0.0", "@next/mdx": "^14.0.3", "@tailwindcss/typography": "^0.5.10", + "@types/node": "^20.10.0", + "@types/react": "^18.2.39", + "@types/react-dom": "^18.2.17", + "@types/webpack-env": "^1.18.4", "autoprefixer": "^10.4.16", + "cheerio": "^1.0.0-rc.12", "clsx": "^2.0.0", "fast-glob": "^3.3.2", "feed": "^4.2.2", - "focus-visible": "^5.2.0", "next": "^14.0.3", - "next-router-mock": "^0.9.10", - "postcss-focus-visible": "^9.0.0", + "next-themes": "^0.2.1", "react": "18.2.0", "react-dom": "18.2.0", "remark-gfm": "^4.0.0", - "tailwindcss": "^3.3.5" + "tailwindcss": "^3.3.5", + "typescript": "^5.3.2" }, "devDependencies": { - "@catppuccin/tailwindcss": "^0.1.6", "eslint": "^8.54.0", "eslint-config-next": "^14.0.3", "prettier": "^3.1.0", - "prettier-plugin-tailwindcss": "^0.5.7" + "prettier-plugin-tailwindcss": "^0.5.7", + "sharp": "^0.32.6" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -67,15 +71,6 @@ "node": ">=6.9.0" } }, - "node_modules/@catppuccin/tailwindcss": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@catppuccin/tailwindcss/-/tailwindcss-0.1.6.tgz", - "integrity": "sha512-V+Y0AwZ5SSyvOVAcDl7Ng30xy+m82OKnEJ+9+kcZZ7lRyXuZrAb2GScdq9XR3v+ggt8qiZ/G4TvaC9cJ88AAXA==", - "dev": true, - "peerDependencies": { - "tailwindcss": ">=3.0.0" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -646,7 +641,6 @@ "version": "20.10.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.0.tgz", "integrity": "sha512-D0WfRmU9TQ8I9PFx9Yc+EBHw+vSpIub4IDvQivcp26PtPrdMGAq5SDcpXEo/epqa/DXotVpekHiLNTg3iaKXBQ==", - "peer": true, "dependencies": { "undici-types": "~5.26.4" } @@ -654,31 +648,41 @@ "node_modules/@types/prop-types": { "version": "15.7.11", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", - "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==", - "peer": true + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" }, "node_modules/@types/react": { "version": "18.2.39", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.39.tgz", "integrity": "sha512-Oiw+ppED6IremMInLV4HXGbfbG6GyziY3kqAwJYOR0PNbkYDmLWQA3a95EhdSmamsvbkJN96ZNN+YD+fGjzSBA==", - "peer": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", "csstype": "^3.0.2" } }, + "node_modules/@types/react-dom": { + "version": "18.2.17", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.17.tgz", + "integrity": "sha512-rvrT/M7Df5eykWFxn6MYt5Pem/Dbyc1N8Y0S9Mrkw2WFCRiqUgw9P7ul2NpwsXCSM1DVdENzdG9J5SreqfAIWg==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/scheduler": { "version": "0.16.8", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", - "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", - "peer": true + "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==" }, "node_modules/@types/unist": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" }, + "node_modules/@types/webpack-env": { + "version": "1.18.4", + "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.18.4.tgz", + "integrity": "sha512-I6e+9+HtWADAWeeJWDFQtdk4EVSAbj6Rtz4q8fJ7mSr1M0jzlFcs8/HZ+Xb5SHzVm1dxH7aUiI+A8kA8Gcrm0A==" + }, "node_modules/@typescript-eslint/parser": { "version": "6.13.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.13.1.tgz", @@ -1276,6 +1280,12 @@ "dequal": "^2.0.3" } }, + "node_modules/b4a": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz", + "integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==", + "dev": true + }, "node_modules/bail": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", @@ -1290,6 +1300,26 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -1298,6 +1328,22 @@ "node": ">=8" } }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1349,6 +1395,30 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -1477,6 +1547,42 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/cheerio": { + "version": "1.0.0-rc.12", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", + "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "htmlparser2": "^8.0.1", + "parse5": "^7.0.0", + "parse5-htmlparser2-tree-adapter": "^7.0.0" + }, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -1514,6 +1620,12 @@ "node": ">= 6" } }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, "node_modules/chrome-trace-event": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", @@ -1545,6 +1657,19 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1563,6 +1688,16 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dev": true, + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, "node_modules/comma-separated-tokens": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", @@ -1599,6 +1734,32 @@ "node": ">= 8" } }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -1613,8 +1774,7 @@ "node_modules/csstype": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", - "peer": true + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, "node_modules/damerau-levenshtein": { "version": "1.0.8", @@ -1650,6 +1810,30 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -1695,6 +1879,15 @@ "node": ">=6" } }, + "node_modules/detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/devlop": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", @@ -1741,6 +1934,57 @@ "node": ">=6.0.0" } }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/electron-to-chromium": { "version": "1.4.595", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.595.tgz", @@ -1752,6 +1996,15 @@ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/enhanced-resolve": { "version": "5.15.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", @@ -1764,6 +2017,17 @@ "node": ">=10.13.0" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/es-abstract": { "version": "1.22.3", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", @@ -2393,6 +2657,15 @@ "node": ">=0.8.x" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -2403,6 +2676,12 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true + }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", @@ -2518,11 +2797,6 @@ "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, - "node_modules/focus-visible": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/focus-visible/-/focus-visible-5.2.0.tgz", - "integrity": "sha512-Rwix9pBtC1Nuy5wysTmKy+UjbDJpIfg8eHjw0rjZ1mX4GNLz1Bmd16uDpI3Gk1i70Fgcs8Csg2lPm8HULFg9DQ==" - }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -2544,6 +2818,12 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2640,6 +2920,12 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "dev": true + }, "node_modules/glob": { "version": "7.1.7", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", @@ -2964,6 +3250,44 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", @@ -3012,6 +3336,12 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, "node_modules/inline-style-parser": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", @@ -3067,6 +3397,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "dev": true + }, "node_modules/is-async-function": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", @@ -4722,6 +5058,18 @@ "node": ">= 0.6" } }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -4742,6 +5090,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -4774,6 +5128,12 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "dev": true + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -4831,15 +5191,34 @@ } } }, - "node_modules/next-router-mock": { - "version": "0.9.10", - "resolved": "https://registry.npmjs.org/next-router-mock/-/next-router-mock-0.9.10.tgz", - "integrity": "sha512-bK6sRb/xGNFgHVUZuvuApn6KJBAKTPiP36A7a9mO77U4xQO5ukJx9WHlU67Tv8AuySd09pk0+Hu8qMVIAmLO6A==", + "node_modules/next-themes": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.2.1.tgz", + "integrity": "sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A==", "peerDependencies": { - "next": ">=10.0.0", - "react": ">=17.0.0" + "next": "*", + "react": "*", + "react-dom": "*" } }, + "node_modules/node-abi": { + "version": "3.51.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.51.0.tgz", + "integrity": "sha512-SQkEP4hmNWjlniS5zdnfIXTk1x7Ome85RDzHlTbBtzE97Gfwz/Ipw4v/Ryk20DWIy3yCNVLVlGKApCnmvYoJbA==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", + "dev": true + }, "node_modules/node-releases": { "version": "2.0.13", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", @@ -4861,6 +5240,17 @@ "node": ">=0.10.0" } }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -5077,6 +5467,29 @@ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==" }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", + "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", + "dependencies": { + "domhandler": "^5.0.2", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -5186,42 +5599,6 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/postcss-focus-visible": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-9.0.0.tgz", - "integrity": "sha512-zA4TbVaIaT8npZBEROhZmlc+GBKE8AELPHXE7i4TmIUEQhw/P/mSJfY9t6tBzpQ1rABeGtEOHYrW4SboQeONMQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "dependencies": { - "postcss-selector-parser": "^6.0.13" - }, - "engines": { - "node": "^14 || ^16 || >=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/postcss-focus-visible/node_modules/postcss-selector-parser": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/postcss-import": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", @@ -5345,6 +5722,60 @@ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, + "node_modules/prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "dev": true, + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prebuild-install/node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/prebuild-install/node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -5469,6 +5900,16 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -5496,6 +5937,12 @@ } ] }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -5505,6 +5952,30 @@ "safe-buffer": "^5.1.0" } }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", @@ -5542,6 +6013,20 @@ "pify": "^2.3.0" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -5884,8 +6369,7 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "peer": true + ] }, "node_modules/safe-regex-test": { "version": "1.0.0", @@ -5985,6 +6469,29 @@ "node": ">= 0.4" } }, + "node_modules/sharp": { + "version": "0.32.6", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz", + "integrity": "sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.2", + "node-addon-api": "^6.1.0", + "prebuild-install": "^7.1.1", + "semver": "^7.5.4", + "simple-get": "^4.0.1", + "tar-fs": "^3.0.4", + "tunnel-agent": "^0.6.0" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -6020,6 +6527,60 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -6081,6 +6642,25 @@ "node": ">=10.0.0" } }, + "node_modules/streamx": { + "version": "2.15.5", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.5.tgz", + "integrity": "sha512-9thPGMkKC2GctCzyCUjME3yR03x2xNo0GPKGkRw2UMYN+gqWa9uqpyNWhmsNCutU5zHmkUum0LsCRQTXUgUCAg==", + "dev": true, + "dependencies": { + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string.prototype.matchall": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", @@ -6341,6 +6921,28 @@ "node": ">=6" } }, + "node_modules/tar-fs": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", + "integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", + "dev": true, + "dependencies": { + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + } + }, + "node_modules/tar-stream": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.6.tgz", + "integrity": "sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==", + "dev": true, + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, "node_modules/terser": { "version": "5.24.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.24.0.tgz", @@ -6487,6 +7089,18 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -6580,8 +7194,6 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz", "integrity": "sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==", - "dev": true, - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -6608,8 +7220,7 @@ "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "peer": true + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, "node_modules/unified": { "version": "11.0.4", diff --git a/package.json b/package.json index 3744c08..fb5d2c0 100644 --- a/package.json +++ b/package.json @@ -17,24 +17,28 @@ "@mdx-js/react": "^3.0.0", "@next/mdx": "^14.0.3", "@tailwindcss/typography": "^0.5.10", + "@types/node": "^20.10.0", + "@types/react": "^18.2.39", + "@types/react-dom": "^18.2.17", + "@types/webpack-env": "^1.18.4", "autoprefixer": "^10.4.16", + "cheerio": "^1.0.0-rc.12", "clsx": "^2.0.0", "fast-glob": "^3.3.2", "feed": "^4.2.2", - "focus-visible": "^5.2.0", "next": "^14.0.3", - "next-router-mock": "^0.9.10", - "postcss-focus-visible": "^9.0.0", + "next-themes": "^0.2.1", "react": "18.2.0", "react-dom": "18.2.0", "remark-gfm": "^4.0.0", - "tailwindcss": "^3.3.5" + "tailwindcss": "^3.3.5", + "typescript": "^5.3.2" }, "devDependencies": { - "@catppuccin/tailwindcss": "^0.1.6", "eslint": "^8.54.0", "eslint-config-next": "^14.0.3", "prettier": "^3.1.0", - "prettier-plugin-tailwindcss": "^0.5.7" + "prettier-plugin-tailwindcss": "^0.5.7", + "sharp": "^0.32.6" } } diff --git a/postcss.config.js b/postcss.config.js index 6573c25..33ad091 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,9 +1,6 @@ module.exports = { plugins: { tailwindcss: {}, - 'postcss-focus-visible': { - replaceWith: '[data-focus-visible-added]', - }, autoprefixer: {}, }, } diff --git a/prettier.config.js b/prettier.config.js index cafb6bb..6b16840 100644 --- a/prettier.config.js +++ b/prettier.config.js @@ -1,5 +1,6 @@ +/** @type {import('prettier').Options} */ module.exports = { singleQuote: true, semi: false, - plugins: [import('prettier-plugin-tailwindcss')], + plugins: ['prettier-plugin-tailwindcss'], } diff --git a/src/app/about/page.tsx b/src/app/about/page.tsx new file mode 100644 index 0000000..217db60 --- /dev/null +++ b/src/app/about/page.tsx @@ -0,0 +1,161 @@ +import { type Metadata } from 'next' +import Image from 'next/image' +import Link from 'next/link' +import clsx from 'clsx' + +import { Container } from '@/components/Container' +import { + GitHubIcon, + LinkedInIcon, + MastodonIcon, + ORCIDIcon, + ResearchGateIcon, +} from '@/components/SVGIcons' +import portraitImage from '@/images/portrait.jpg' + +function SocialLink({ + className, + href, + children, + icon: Icon, +}: { + className?: string + href: string + icon: React.ComponentType<{ className?: string }> + children: React.ReactNode +}) { + return ( +
  • + + + {children} + +
  • + ) +} + +function MailIcon(props: React.ComponentPropsWithoutRef<'svg'>) { + return ( + + ) +} + +export const metadata: Metadata = { + title: 'About', + description: + 'I’m dr. Jip J. Dekker, a problem solver using optimization technologies.', +} + +export default function About() { + return ( + +
    +
    +
    + +
    +
    +
    +

    + I’m dr. Jip J. Dekker, a problem solver using optimization + technologies. +

    +
    +

    + I’m a computer scientist at Monash University specializing in + optimization and devoted to developing cutting-edge tools and + modelling languages that simplify the process of solving complex + problems. With a passion for advancing the field, I contribute to + the optimization field, enhancing its efficiency, and facilitating + its practical application. +

    +

    + Building from a foundation in constraint programming, I have + gained experience in Boolean satisfiability, mathematical + modelling, local search, various hybrid method. With the wide + range of optimization technologies at my fingertips, it enables me + to approach optimization challenges from many angles. This allows + me to facilitate the creation of innovative software solutions + that streamline the formulation, solution, and analysis of + optimization problems. +

    +

    + At the heart of my work is a commitment to making optimization + more accessible and user-friendly. By developing intuitive tools + and modelling languages, I want to empower researchers, + practitioners, and anyone willing to learn to effectively address + complex optimization challenges across a wide range of domains. I + hope that my work not only enhances the effectiveness of + optimization technologies, but also fosters innovation and + improvements in other industries. +

    +

    + When I’m not solving optimization problems, I love bird watching, + music, and cycling. The beauty of the avian world has captivated + me ever since I moved to Australia. Music brings me solace. I’m + always looking for new songs with interesting melodies or striking + lyrics. Cycling always gives me a sense of freedom. You find the + most wonderful places, if you stray from the beaten track even + slightly. These pursuits bring me joy and inspiration. +

    +
    +
    +
    +
      + + Follow me on GitHub + + + Follow me on Mastodon + + + Connect with me on LinkedIn + + + Find me on ORCID + + + Follow me on ResearchGate + + + jip.dekker@monash.edu + +
    +
    +
    +
    + ) +} diff --git a/src/pages/articles/2017-02-custom-dtrace-instrumentation.mdx b/src/app/articles/2017-02-custom-dtrace-instrumentation/page.mdx similarity index 97% rename from src/pages/articles/2017-02-custom-dtrace-instrumentation.mdx rename to src/app/articles/2017-02-custom-dtrace-instrumentation/page.mdx index 5d29cf5..78b1181 100644 --- a/src/pages/articles/2017-02-custom-dtrace-instrumentation.mdx +++ b/src/app/articles/2017-02-custom-dtrace-instrumentation/page.mdx @@ -1,14 +1,19 @@ import { ArticleLayout } from '@/components/ArticleLayout' -export const meta = { +export const dynamic = 'force-static' +export const article = { author: 'Jip J. Dekker', date: '2017-02-24', title: 'Implementing custom DTrace instrumentation', description: 'DTrace (and SystemTap) are often the “go to” when adding tracing in high performance environments such as for example operating systems. This note discusses adding instrumentation to your own application, so you can take advantage of these powerful tools.', } +export const metadata = { + title: article.title, + description: article.description, +} -export default (props) => +export default (props) => Last semester I had a chance to work with DTrace. In particular, I implemented custom DTrace instrumentation in Encore and [Pony](http://www.ponylang.org/). diff --git a/src/pages/articles/2022-08-homebrew-minizinc.mdx b/src/app/articles/2022-08-homebrew-minizinc/page.mdx similarity index 94% rename from src/pages/articles/2022-08-homebrew-minizinc.mdx rename to src/app/articles/2022-08-homebrew-minizinc/page.mdx index a648eab..143eb44 100644 --- a/src/pages/articles/2022-08-homebrew-minizinc.mdx +++ b/src/app/articles/2022-08-homebrew-minizinc/page.mdx @@ -1,14 +1,19 @@ import { ArticleLayout } from '@/components/ArticleLayout' -export const meta = { +export const dynamic = 'force-static' +export const article = { author: 'Jip J. Dekker', date: '2022-08-15', title: 'A Homebrew Tap for MiniZinc Solvers', description: "I'm proposing a Homebrew tap to make it easier for users to install different MiniZinc solvers. The tap already contains many of the open source solvers that are current contenders in the MiniZinc challenge, and I'm hoping to add any others that fit the infrastructure.", } +export const metadata = { + title: article.title, + description: article.description, +} -export default (props) => +export default (props) => TLDR; I'm proposing a [Homebrew](https://brew.sh/) tap to make it easier for users to install different MiniZinc solvers. The tap already contains many of the open source solvers that are current contenders in the MiniZinc challenge, and I'm hoping to add any others that fit the infrastructure. diff --git a/src/app/articles/page.tsx b/src/app/articles/page.tsx new file mode 100644 index 0000000..3b79d5d --- /dev/null +++ b/src/app/articles/page.tsx @@ -0,0 +1,60 @@ +import { type Metadata } from 'next' + +import { Card } from '@/components/Card' +import { SimpleLayout } from '@/components/SimpleLayout' +import { type ArticleWithSlug, getAllArticles } from '@/lib/articles' +import { formatDate } from '@/lib/formatDate' + +function Article({ article }: { article: ArticleWithSlug }) { + return ( +
    + + + {article.title} + + + {formatDate(article.date)} + + {article.description} + Read article + + + {formatDate(article.date)} + +
    + ) +} + +export const metadata: Metadata = { + title: 'Articles', + description: + 'All of my long-form thoughts on programming, leadership, product design, and more, collected in chronological order.', +} + +export default async function ArticlesIndex() { + let articles = await getAllArticles() + + return ( + +
    +
    + {articles.map((article) => ( +
    + ))} +
    +
    +
    + ) +} diff --git a/public/favicon.ico b/src/app/favicon.ico similarity index 100% rename from public/favicon.ico rename to src/app/favicon.ico diff --git a/src/app/feed.xml/route.ts b/src/app/feed.xml/route.ts new file mode 100644 index 0000000..d8a9a3a --- /dev/null +++ b/src/app/feed.xml/route.ts @@ -0,0 +1,62 @@ +import { getAllArticles } from '@/lib/articles' +import assert from 'assert' +import { Feed } from 'feed' + +export async function GET(req: Request) { + let siteUrl = process.env.NEXT_PUBLIC_SITE_URL + + if (!siteUrl) { + throw Error('Missing NEXT_PUBLIC_SITE_URL environment variable') + } + + let author = { + name: 'Jip J. Dekker', + email: 'jip.dekker@monash.edu', + } + + let feed = new Feed({ + title: author.name, + description: + 'The collection of writing by Jip about optimization, programming language, and general computer science', + author, + id: siteUrl, + link: siteUrl, + image: `${siteUrl}/favicon.ico`, + favicon: `${siteUrl}/favicon.ico`, + copyright: `All rights reserved ${new Date().getFullYear()}`, + feedLinks: { + rss2: `${siteUrl}/feed.xml`, + }, + }) + + let articles = await getAllArticles() + + for (let article of articles) { + let publicUrl = `${siteUrl}/articles/${article.slug}` + let title = article.title + let date = article.date + let description = article.description + + assert(typeof title === 'string') + assert(typeof date === 'string') + assert(typeof description === 'string') + + feed.addItem({ + title, + id: publicUrl, + link: publicUrl, + description, + author: [author], + contributor: [author], + date: new Date(date), + }) + } + + return new Response(feed.rss2(), { + status: 200, + headers: { + 'content-type': 'application/xml', + 'cache-control': 's-maxage=31556952', + }, + }) +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx new file mode 100644 index 0000000..6dbd166 --- /dev/null +++ b/src/app/layout.tsx @@ -0,0 +1,38 @@ +import { type Metadata } from 'next' + +import { Providers } from '@/app/providers' +import { Layout } from '@/components/Layout' + +import '@/styles/tailwind.css' + +export const metadata: Metadata = { + title: { + template: '%s - Jip J. Dekker', + default: 'Jip J. Dekker - Optimisation Expert & Computer Scientist', + }, + description: + 'I’m Jip, a researcher at the OPTIMA ARC research centre and Monash University, where we aim to make complex decisions easier through decision support and data insights. We design state-of-the-art optimization techniques, such as the MiniZinc modelling language, ready to be used in industry.', + alternates: { + types: { + 'application/rss+xml': `${process.env.NEXT_PUBLIC_SITE_URL}/feed.xml`, + }, + }, +} + +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + + +
    + {children} +
    +
    + + + ) +} diff --git a/src/app/not-found.tsx b/src/app/not-found.tsx new file mode 100644 index 0000000..4067f6f --- /dev/null +++ b/src/app/not-found.tsx @@ -0,0 +1,23 @@ +import { Button } from '@/components/Button' +import { Container } from '@/components/Container' + +export default function NotFound() { + return ( + +
    +

    + 404 +

    +

    + Page not found +

    +

    + Sorry, we couldn’t find the page you’re looking for. +

    + +
    +
    + ) +} diff --git a/src/pages/index.jsx b/src/app/page.tsx similarity index 65% rename from src/pages/index.jsx rename to src/app/page.tsx index 86f3525..e004343 100644 --- a/src/pages/index.jsx +++ b/src/app/page.tsx @@ -1,12 +1,10 @@ -import Head from 'next/head' -import Image from 'next/image' +import Image, { type ImageProps } from 'next/image' import Link from 'next/link' import clsx from 'clsx' import { Card } from '@/components/Card' import { Container } from '@/components/Container' import { - ArrowDownIcon, BriefcaseIcon, GitHubIcon, LinkedInIcon, @@ -23,12 +21,10 @@ import image2 from '@/images/photos/image-4.jpg' import image3 from '@/images/photos/image-2.jpg' import image4 from '@/images/photos/image-3.jpg' import image5 from '@/images/photos/image-5.jpg' +import { type ArticleWithSlug, getAllArticles } from '@/lib/articles' import { formatDate } from '@/lib/formatDate' -import { generateRssFeed } from '@/lib/generateRssFeed' -import { getAllArticles } from '@/lib/getAllArticles' -import { Button } from '@/components/Button' -function Article({ article }) { +function Article({ article }: { article: ArticleWithSlug }) { return ( @@ -43,7 +39,12 @@ function Article({ article }) { ) } -function SocialLink({ icon: Icon, ...props }) { +function SocialLink({ + icon: Icon, + ...props +}: React.ComponentPropsWithoutRef & { + icon: React.ComponentType<{ className?: string }> +}) { return ( @@ -51,8 +52,53 @@ function SocialLink({ icon: Icon, ...props }) { ) } +interface Role { + company: string + title: string + logo: ImageProps['src'] + start: string | { label: string; dateTime: string } + end: string | { label: string; dateTime: string } +} + +function Role({ role }: { role: Role }) { + let startLabel = + typeof role.start === 'string' ? role.start : role.start.label + let startDate = + typeof role.start === 'string' ? role.start : role.start.dateTime + + let endLabel = typeof role.end === 'string' ? role.end : role.end.label + let endDate = typeof role.end === 'string' ? role.end : role.end.dateTime + + return ( +
  • +
    + +
    +
    +
    Company
    +
    + {role.company} +
    +
    Role
    +
    + {role.title} +
    +
    Date
    +
    + {' '} + {' '} + +
    +
    +
  • + ) +} + function Resume() { - let resume = [ + let resume: Array = [ { company: 'OPTIMA & Monash University', title: 'Research Fellow', @@ -60,7 +106,7 @@ function Resume() { start: '2021', end: { label: 'Present', - dateTime: new Date().getFullYear(), + dateTime: new Date().getFullYear().toString(), }, }, { @@ -94,53 +140,14 @@ function Resume() {
      {resume.map((role, roleIndex) => ( -
    1. -
      - -
      -
      -
      Company
      -
      - {role.company} -
      -
      Role
      -
      - {role.title} -
      -
      Date
      -
      - {' '} - {' '} - -
      -
      -
    2. + ))}
    - - - {/* + */} ) @@ -173,18 +180,11 @@ function Photos() { ) } -export default function Home({ articles }) { +export default async function Home() { + let articles = (await getAllArticles()).slice(0, 4) + return ( <> - - - Jip J. Dekker - Optimisation Expert & Programming Language Designer - - -

    @@ -242,17 +242,3 @@ export default function Home({ articles }) { ) } - -export async function getStaticProps() { - if (process.env.NODE_ENV === 'production') { - await generateRssFeed() - } - - return { - props: { - articles: (await getAllArticles()) - .slice(0, 4) - .map(({ component, ...meta }) => meta), - }, - } -} diff --git a/src/app/projects/page.tsx b/src/app/projects/page.tsx new file mode 100644 index 0000000..8ceaf60 --- /dev/null +++ b/src/app/projects/page.tsx @@ -0,0 +1,93 @@ +import { type Metadata } from 'next' +import Image from 'next/image' + +import { Card } from '@/components/Card' +import { SimpleLayout } from '@/components/SimpleLayout' +import { LinkIcon } from '@/components/SVGIcons' +import logoChuffed from '@/images/logos/chuffed.png' +import logoMiniZinc from '@/images/logos/minizinc.svg' +import logoMZNPy from '@/images/logos/minizinc-python.svg' +import logoPindakaas from '@/images/logos/pindakaas.svg' +import logoShackle from '@/images/logos/shackle.svg' + +const projects = [ + { + name: 'MiniZinc', + description: + 'A constraint modelling language for almost all types of optimization solvers.', + link: { href: 'http://www.minizinc.org', label: 'minizinc.org' }, + logo: logoMiniZinc, + }, + { + name: 'Chuffed', + description: 'The solver that brought Lazy Clause Generation to the world.', + link: { href: 'https://github.com/chuffed/chuffed', label: 'github.com' }, + logo: logoChuffed, + }, + { + name: 'Shackle', + description: 'The next generation of constraint model rewriting tooling.', + link: { + href: 'https://github.com/shackle-rs/shackle', + label: 'github.com', + }, + logo: logoShackle, + }, + { + name: 'Pindakaas', + description: + 'A library that helps you create state-of-the-art encodings for Boolean satisfiability solvers.', + link: { href: '#', label: 'TBA' }, + logo: logoPindakaas, + }, + { + name: 'MiniZinc Python', + description: + 'Easily run MiniZinc from Python, with incremental solving and direct data access.', + link: { + href: 'https://github.com/MiniZinc/minizinc-python', + label: 'github.com', + }, + logo: logoMZNPy, + }, +] + +export const metadata: Metadata = { + title: 'Projects', + description: 'From my brain to your computer', +} + +export default function Projects() { + return ( + +
      + {projects.map((project) => ( + +
      + +
      +

      + {project.name} +

      + {project.description} +

      + + {project.link.label} +

      +
      + ))} +
    +
    + ) +} diff --git a/src/app/providers.tsx b/src/app/providers.tsx new file mode 100644 index 0000000..028e29d --- /dev/null +++ b/src/app/providers.tsx @@ -0,0 +1,30 @@ +'use client' + +import { createContext, useEffect, useRef } from 'react' +import { usePathname } from 'next/navigation' +import { ThemeProvider, useTheme } from 'next-themes' + +function usePrevious(value: T) { + let ref = useRef() + + useEffect(() => { + ref.current = value + }, [value]) + + return ref.current +} + +export const AppContext = createContext<{ previousPathname?: string }>({}) + +export function Providers({ children }: { children: React.ReactNode }) { + let pathname = usePathname() + let previousPathname = usePrevious(pathname) + + return ( + + + {children} + + + ) +} diff --git a/src/app/speaking/page.tsx b/src/app/speaking/page.tsx new file mode 100644 index 0000000..dbaf66e --- /dev/null +++ b/src/app/speaking/page.tsx @@ -0,0 +1,98 @@ +import { type Metadata } from 'next' + +import { Card } from '@/components/Card' +import { Section } from '@/components/Section' +import { SimpleLayout } from '@/components/SimpleLayout' + +function SpeakingSection({ + children, + ...props +}: React.ComponentPropsWithoutRef) { + return ( +
    +
    {children}
    +
    + ) +} + +function Appearance({ + title, + description, + event, + cta, + href, +}: { + title: string + description: string + event: string + cta: string + href: string +}) { + return ( + + + {title} + + {event} + {description} + {cta} + + ) +} + +export const metadata: Metadata = { + title: 'Speaking', + description: + 'I’ve spoken at events all around the world and been interviewed for many podcasts.', +} + +export default function Speaking() { + return ( + +
    + + + + + + + + + +
    +
    + ) +} diff --git a/src/app/uses/page.tsx b/src/app/uses/page.tsx new file mode 100644 index 0000000..778e326 --- /dev/null +++ b/src/app/uses/page.tsx @@ -0,0 +1,123 @@ +import { Card } from '@/components/Card' +import { Section } from '@/components/Section' +import { SimpleLayout } from '@/components/SimpleLayout' + +function ToolsSection({ + children, + ...props +}: React.ComponentPropsWithoutRef) { + return ( +
    +
      + {children} +
    +
    + ) +} + +function Tool({ + title, + href, + children, +}: { + title: string + href?: string + children: React.ReactNode +}) { + return ( + + + {title} + + {children} + + ) +} + +export const metadata = { + title: 'Uses', + description: 'Software I use, gadgets I love, and other things I recommend.', +} + +export default function Uses() { + return ( + +
    + + + I was using an Intel-based 16” MacBook Pro prior to this and the + difference is night and day. I’ve never heard the fans turn on a + single time, even under the incredibly heavy loads I put it through + with our various launch simulations. + + + The only display on the market if you want something HiDPI and + bigger than 27”. When you’re working at planetary scale, every pixel + you can get counts. + + + They don’t make keyboards the way they used to. I buy these any time + I see them go up for sale and keep them in storage in case I need + parts or need to retire my main. + + + Something about all the gestures makes me feel like a wizard with + special powers. I really like feeling like a wizard with special + powers. + + + If I’m going to slouch in the worst ergonomic position imaginable + all day, I might as well do it in an expensive chair. + + + + + I don’t care if it’s missing all of the fancy IDE features everyone + else relies on, Sublime Text is still the best text editor ever + made. + + + I’m honestly not even sure what features I get with this that aren’t + just part of the macOS Terminal but it’s what I use. + + + Great software for working with databases. Has saved me from + building about a thousand admin interfaces for my various projects + over the years. + + + + + We started using Figma as just a design tool but now it’s become our + virtual whiteboard for the entire company. Never would have expected + the collaboration features to be the real hook. + + + + + It’s not the newest kid on the block but it’s still the fastest. The + Sublime Text of the application launcher world. + + + Using a daily notes system instead of trying to keep things + organized by topics has been super powerful for me. And with + Reflect, it’s still easy for me to keep all of that stuff + discoverable by topic even though all of my writing happens in the + daily note. + + + Great tool for scheduling meetings while protecting my calendar and + making sure I still have lots of time for deep work during the week. + + + Simple tool for blocking distracting websites when I need to just do + the work and get some momentum going. + + +
    +
    + ) +} diff --git a/src/components/ArticleLayout.jsx b/src/components/ArticleLayout.jsx deleted file mode 100644 index a6dc640..0000000 --- a/src/components/ArticleLayout.jsx +++ /dev/null @@ -1,60 +0,0 @@ -import Head from 'next/head' -import { useRouter } from 'next/router' - -import { Container } from '@/components/Container' -import { Prose } from '@/components/Prose' -import { formatDate } from '@/lib/formatDate' -import { ArrowLeftIcon } from '@/components/SVGIcons' - -export function ArticleLayout({ - children, - meta, - isRssFeed = false, - previousPathname, -}) { - let router = useRouter() - - if (isRssFeed) { - return children - } - - return ( - <> - - {`${meta.title} - Jip J. Dekker`} - - - -
    -
    - {previousPathname && ( - - )} -
    -
    -

    - {meta.title} -

    - -
    - {children} -
    -
    -
    -
    - - ) -} diff --git a/src/components/ArticleLayout.tsx b/src/components/ArticleLayout.tsx new file mode 100644 index 0000000..5a62546 --- /dev/null +++ b/src/components/ArticleLayout.tsx @@ -0,0 +1,58 @@ +'use client' + +import { useContext } from 'react' +import { useRouter } from 'next/navigation' + +import { AppContext } from '@/app/providers' +import { Container } from '@/components/Container' +import { Prose } from '@/components/Prose' +import { type ArticleWithSlug } from '@/lib/articles' +import { formatDate } from '@/lib/formatDate' +import { ArrowLeftIcon } from './SVGIcons' + +export function ArticleLayout({ + article, + children, +}: { + article: ArticleWithSlug + children: React.ReactNode +}) { + let router = useRouter() + let { previousPathname } = useContext(AppContext) + + return ( + +
    +
    + {previousPathname && ( + + )} +
    +
    +

    + {article.title} +

    + +
    + + {children} + +
    +
    +
    +
    + ) +} diff --git a/src/components/Button.jsx b/src/components/Button.tsx similarity index 68% rename from src/components/Button.jsx rename to src/components/Button.tsx index 94e6ca9..a17201c 100644 --- a/src/components/Button.jsx +++ b/src/components/Button.tsx @@ -8,16 +8,27 @@ const variantStyles = { 'bg-zinc-50 font-medium text-zinc-900 hover:bg-zinc-100 active:bg-zinc-100 active:text-zinc-900/60 dark:bg-zinc-800/50 dark:text-zinc-300 dark:hover:bg-zinc-800 dark:hover:text-zinc-50 dark:active:bg-zinc-800/50 dark:active:text-zinc-50/70', } -export function Button({ variant = 'primary', className, href, ...props }) { +type ButtonProps = { + variant?: keyof typeof variantStyles +} & ( + | (React.ComponentPropsWithoutRef<'button'> & { href?: undefined }) + | React.ComponentPropsWithoutRef +) + +export function Button({ + variant = 'primary', + className, + ...props +}: ButtonProps) { className = clsx( 'inline-flex items-center gap-2 justify-center rounded-md py-2 px-3 text-sm outline-offset-2 transition active:transition-none', variantStyles[variant], className, ) - return href ? ( - - ) : ( + return typeof props.href === 'undefined' ? (