]> git.otsuka.systems Git - cotsuka.github.io/commitdiff
v2.1.0
authorCameron Otsuka <cameron@otsuka.haus>
Mon, 17 Nov 2025 01:15:51 +0000 (17:15 -0800)
committerCameron Otsuka <cameron@otsuka.haus>
Mon, 17 Nov 2025 01:15:51 +0000 (17:15 -0800)
85 files changed:
astro.config.mjs
bun.lock
content/build-weekly-roundup/2025-04.md [moved from content/links/build-weekly-roundup-2025-week-4.md with 100% similarity]
content/build-weekly-roundup/2025-05.md [moved from content/links/build-weekly-roundup-2025-week-5.md with 100% similarity]
content/build-weekly-roundup/2025-06.mdx [moved from content/links/build-weekly-roundup-2025-week-6.mdx with 100% similarity]
content/build-weekly-roundup/2025-07.mdx [moved from content/links/build-weekly-roundup-2025-week-7.mdx with 100% similarity]
content/build-weekly-roundup/2025-08.mdx [moved from content/links/build-weekly-roundup-2025-week-8.mdx with 100% similarity]
content/build-weekly-roundup/2025-11.mdx [moved from content/links/build-weekly-roundup-2025-week-11.mdx with 100% similarity]
content/build-weekly-roundup/2025-12.mdx [moved from content/links/build-weekly-roundup-2025-week-12.mdx with 100% similarity]
content/build-weekly-roundup/2025-14.mdx [moved from content/links/build-weekly-roundup-2025-week-14.mdx with 100% similarity]
content/build-weekly-roundup/2025-15.mdx [moved from content/links/build-weekly-roundup-2025-week-15.mdx with 100% similarity]
content/build-weekly-roundup/2025-17.mdx [moved from content/links/build-weekly-roundup-2025-week-17.mdx with 100% similarity]
content/build-weekly-roundup/2025-18.mdx [moved from content/links/build-weekly-roundup-2025-week-18.mdx with 100% similarity]
content/build-weekly-roundup/2025-19.mdx [moved from content/links/build-weekly-roundup-2025-week-19.mdx with 100% similarity]
content/build-weekly-roundup/2025-20.mdx [moved from content/links/build-weekly-roundup-2025-week-20.mdx with 100% similarity]
content/build-weekly-roundup/2025-21.mdx [moved from content/links/build-weekly-roundup-2025-week-21.mdx with 100% similarity]
content/build-weekly-roundup/2025-23.mdx [moved from content/links/build-weekly-roundup-2025-week-23.mdx with 100% similarity]
content/build-weekly-roundup/2025-24.mdx [moved from content/links/build-weekly-roundup-2025-week-24.mdx with 100% similarity]
content/build-weekly-roundup/2025-25.mdx [moved from content/links/build-weekly-roundup-2025-week-25.mdx with 100% similarity]
content/build-weekly-roundup/2025-26.mdx [moved from content/links/build-weekly-roundup-2025-week-26.mdx with 100% similarity]
content/build-weekly-roundup/2025-29.mdx [moved from content/links/build-weekly-roundup-2025-week-29.mdx with 100% similarity]
content/build-weekly-roundup/2025-30.mdx [moved from content/links/build-weekly-roundup-2025-week-30.mdx with 100% similarity]
content/build-weekly-roundup/2025-33.mdx [moved from content/links/build-weekly-roundup-2025-week-33.mdx with 100% similarity]
content/build-weekly-roundup/2025-36.mdx [moved from content/links/build-weekly-roundup-2025-week-36.mdx with 100% similarity]
content/build-weekly-roundup/2025-37.mdx [moved from content/links/build-weekly-roundup-2025-week-37.mdx with 100% similarity]
content/build-weekly-roundup/2025-38.mdx [moved from content/links/build-weekly-roundup-2025-week-38.mdx with 100% similarity]
content/build-weekly-roundup/2025-39.mdx [moved from content/links/build-weekly-roundup-2025-week-39.mdx with 100% similarity]
content/build-weekly-roundup/2025-40.mdx [moved from content/links/build-weekly-roundup-2025-week-40.mdx with 100% similarity]
content/build-weekly-roundup/2025-41.mdx [moved from content/links/build-weekly-roundup-2025-week-41.mdx with 100% similarity]
content/build-weekly-roundup/2025-42.mdx [moved from content/links/build-weekly-roundup-2025-week-42.mdx with 100% similarity]
content/build-weekly-roundup/2025-43.mdx [moved from content/links/build-weekly-roundup-2025-week-43.mdx with 100% similarity]
content/build-weekly-roundup/2025-44.mdx [moved from content/links/build-weekly-roundup-2025-week-44.mdx with 100% similarity]
content/build-weekly-roundup/2025-45.mdx [moved from content/links/build-weekly-roundup-2025-week-45.mdx with 100% similarity]
content/build-weekly-roundup/2025-46.mdx [moved from content/links/build-weekly-roundup-2025-week-46.mdx with 100% similarity]
content/reviews/a-complete-unknown.mdx
content/reviews/bugonia.md
content/reviews/burning.md
content/reviews/caught-stealing.md
content/reviews/challengers.md
content/reviews/conclave.md
content/reviews/death-becomes-her.md
content/reviews/den-of-thieves-pantera.md
content/reviews/f1-the-movie.md
content/reviews/fallen-angels/index.mdx
content/reviews/hunchback-of-notre-dame.md
content/reviews/its-whats-inside.md
content/reviews/jurassic-park.md
content/reviews/materialists.md
content/reviews/nosferatu.md
content/reviews/one-battle-after-another.mdx
content/reviews/perfect-days.md
content/reviews/problemista.md
content/reviews/sinners.md
content/reviews/star-wars-episode-iii-revenge-of-the-sith.md
content/reviews/subservience.md
content/reviews/superman.mdx
content/reviews/the-apprentice.md
content/reviews/the-boy-and-the-heron.md
content/reviews/warfare.md
content/reviews/wicked.md
data/metadata.json [deleted file]
package.json
src/components/footer.astro
src/components/head/article.astro
src/components/head/base.astro
src/components/metadata.astro
src/components/navigation.astro
src/components/ratingdistribution/chart.tsx
src/components/ratingdistribution/component.astro
src/content.config.ts
src/pages/articles/[date]-[id]/index.astro
src/pages/articles/[date]-[id]/opengraph.png.ts
src/pages/articles/index.astro
src/pages/build-weekly-roundup/[id]/index.astro [new file with mode: 0644]
src/pages/build-weekly-roundup/[id]/opengraph.png.ts [moved from src/pages/links/[date]-[id]/opengraph.png.ts with 87% similarity]
src/pages/build-weekly-roundup/index.astro [new file with mode: 0644]
src/pages/feed.xml.ts
src/pages/index.astro
src/pages/links/[date]-[id]/index.astro [deleted file]
src/pages/links/index.astro [deleted file]
src/pages/reviews/[type]/[id]/index.astro [moved from src/pages/reviews/[date]-[id]/index.astro with 76% similarity]
src/pages/reviews/[type]/[id]/opengraph.png.ts [moved from src/pages/reviews/[date]-[id]/opengraph.png.ts with 88% similarity]
src/pages/reviews/index.astro
src/utils/globals.ts [new file with mode: 0644]
tsconfig.json

index e368fc12c01955b18c03590659ff238e71ebca6a..521c454905529254c8a25e5b8b0bdc6090f23894 100644 (file)
@@ -2,13 +2,13 @@
 import { defineConfig } from 'astro/config';
 
 import mdx from '@astrojs/mdx';
+import react from '@astrojs/react';
 import sitemap from '@astrojs/sitemap';
 
-import react from '@astrojs/react';
 
 export default defineConfig({
   site: 'https://cameron.otsuka.systems',
-  integrations: [mdx(), sitemap(), react()],
+  integrations: [mdx(), react(), sitemap()],
   markdown: {
     shikiConfig: {
       theme: 'monokai'
index 9f93c12c8ae140e621329598c7a1a99280e2d9a4..02d63f06de24348c715f9dc6e582bdb6b5fd82c8 100644 (file)
--- a/bun.lock
+++ b/bun.lock
@@ -1,42 +1,43 @@
 {
   "lockfileVersion": 1,
+  "configVersion": 0,
   "workspaces": {
     "": {
       "name": "cotsuka.github.io",
       "dependencies": {
-        "@astrojs/mdx": "4.3.7",
-        "@astrojs/react": "4.4.0",
-        "@astrojs/rss": "^4.0.12",
+        "@astrojs/mdx": "4.3.10",
+        "@astrojs/react": "4.4.2",
+        "@astrojs/rss": "4.0.13",
         "@astrojs/sitemap": "3.6.0",
         "@fontsource-variable/public-sans": "^5.2.7",
         "@fontsource-variable/source-code-pro": "^5.2.7",
-        "@types/react": "^19.2.2",
-        "@types/react-dom": "^19.2.1",
+        "@types/react": "^19.2.5",
+        "@types/react-dom": "^19.2.3",
         "@vercel/og": "^0.6.8",
-        "astro": "5.14.5",
+        "astro": "5.15.8",
         "react": "^19.2.0",
         "react-dom": "^19.2.0",
-        "recharts": "^3.2.1",
+        "recharts": "^3.4.1",
       },
       "devDependencies": {
-        "@types/bun": "^1.2.23",
+        "@types/bun": "^1.3.2",
       },
     },
   },
   "packages": {
-    "@astrojs/compiler": ["@astrojs/compiler@2.12.2", "", {}, "sha512-w2zfvhjNCkNMmMMOn5b0J8+OmUaBL1o40ipMvqcG6NRpdC+lKxmTi48DT8Xw0SzJ3AfmeFLB45zXZXtmbsjcgw=="],
+    "@astrojs/compiler": ["@astrojs/compiler@2.13.0", "", {}, "sha512-mqVORhUJViA28fwHYaWmsXSzLO9osbdZ5ImUfxBarqsYdMlPbqAqGJCxsNzvppp1BEzc1mJNjOVvQqeDN8Vspw=="],
 
     "@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.7.4", "", {}, "sha512-lDA9MqE8WGi7T/t2BMi+EAXhs4Vcvr94Gqx3q15cFEz8oFZMO4/SFBqYr/UcmNlvW+35alowkVj+w9VhLvs5Cw=="],
 
     "@astrojs/markdown-remark": ["@astrojs/markdown-remark@6.3.8", "", { "dependencies": { "@astrojs/internal-helpers": "0.7.4", "@astrojs/prism": "3.3.0", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.0", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-smartypants": "^3.0.2", "shiki": "^3.13.0", "smol-toml": "^1.4.2", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", "unist-util-visit": "^5.0.0", "unist-util-visit-parents": "^6.0.1", "vfile": "^6.0.3" } }, "sha512-uFNyFWadnULWK2cOw4n0hLKeu+xaVWeuECdP10cQ3K2fkybtTlhb7J7TcScdjmS8Yps7oje9S/ehYMfZrhrgCg=="],
 
-    "@astrojs/mdx": ["@astrojs/mdx@4.3.7", "", { "dependencies": { "@astrojs/markdown-remark": "6.3.8", "@mdx-js/mdx": "^3.1.1", "acorn": "^8.15.0", "es-module-lexer": "^1.7.0", "estree-util-visit": "^2.0.0", "hast-util-to-html": "^9.0.5", "kleur": "^4.1.5", "rehype-raw": "^7.0.0", "remark-gfm": "^4.0.1", "remark-smartypants": "^3.0.2", "source-map": "^0.7.6", "unist-util-visit": "^5.0.0", "vfile": "^6.0.3" }, "peerDependencies": { "astro": "^5.0.0" } }, "sha512-5SRmvMyT/UMWaU2eoD+htnXtE2mUZZEH2K/nEzhuEy+iCsOSuS/DUry59WuKUJRQETi1mgJFdNR4dZLJHYVuRA=="],
+    "@astrojs/mdx": ["@astrojs/mdx@4.3.10", "", { "dependencies": { "@astrojs/markdown-remark": "6.3.8", "@mdx-js/mdx": "^3.1.1", "acorn": "^8.15.0", "es-module-lexer": "^1.7.0", "estree-util-visit": "^2.0.0", "hast-util-to-html": "^9.0.5", "picocolors": "^1.1.1", "rehype-raw": "^7.0.0", "remark-gfm": "^4.0.1", "remark-smartypants": "^3.0.2", "source-map": "^0.7.6", "unist-util-visit": "^5.0.0", "vfile": "^6.0.3" }, "peerDependencies": { "astro": "^5.0.0" } }, "sha512-2T5+XIr7PMqMeXhRofXY5NlY4lA0Km+wkfsqmr9lq5KXUHpGlKPQ9dlDZJP9E/CtljJyEBNS17zq66LrIJ1tiQ=="],
 
     "@astrojs/prism": ["@astrojs/prism@3.3.0", "", { "dependencies": { "prismjs": "^1.30.0" } }, "sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ=="],
 
-    "@astrojs/react": ["@astrojs/react@4.4.0", "", { "dependencies": { "@vitejs/plugin-react": "^4.7.0", "ultrahtml": "^1.6.0", "vite": "^6.3.6" }, "peerDependencies": { "@types/react": "^17.0.50 || ^18.0.21 || ^19.0.0", "@types/react-dom": "^17.0.17 || ^18.0.6 || ^19.0.0", "react": "^17.0.2 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0" } }, "sha512-RzblkVImAFdV1C0AWsSWzS70Z0FMtW2p0XXkNYu3QePfyVJta3JIy8m8jY8271etaCZtpFjsE2UaiHGZIBm6nw=="],
+    "@astrojs/react": ["@astrojs/react@4.4.2", "", { "dependencies": { "@vitejs/plugin-react": "^4.7.0", "ultrahtml": "^1.6.0", "vite": "^6.4.1" }, "peerDependencies": { "@types/react": "^17.0.50 || ^18.0.21 || ^19.0.0", "@types/react-dom": "^17.0.17 || ^18.0.6 || ^19.0.0", "react": "^17.0.2 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0" } }, "sha512-1tl95bpGfuaDMDn8O3x/5Dxii1HPvzjvpL2YTuqOOrQehs60I2DKiDgh1jrKc7G8lv+LQT5H15V6QONQ+9waeQ=="],
 
-    "@astrojs/rss": ["@astrojs/rss@4.0.12", "", { "dependencies": { "fast-xml-parser": "^5.2.0", "kleur": "^4.1.5" } }, "sha512-O5yyxHuDVb6DQ6VLOrbUVFSm+NpObulPxjs6XT9q3tC+RoKbN4HXMZLpv0LvXd1qdAjzVgJ1NFD+zKHJNDXikw=="],
+    "@astrojs/rss": ["@astrojs/rss@4.0.13", "", { "dependencies": { "fast-xml-parser": "^5.3.0", "picocolors": "^1.1.1" } }, "sha512-ugW4DmGn8kgfl8/qecU3EcKCAuEBrZqY7eYfa6at0sY7HGEwRdzsOafLE437RwDMP2ZuxfKnCNABs99YVhX0kg=="],
 
     "@astrojs/sitemap": ["@astrojs/sitemap@3.6.0", "", { "dependencies": { "sitemap": "^8.0.0", "stream-replace-string": "^2.0.0", "zod": "^3.25.76" } }, "sha512-4aHkvcOZBWJigRmMIAJwRQXBS+ayoP5z40OklTXYXhUDhwusz+DyDl+nSshY6y9DvkVEavwNcFO8FD81iGhXjg=="],
 
 
     "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="],
 
-    "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="],
+    "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
 
     "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="],
 
     "@babel/helpers": ["@babel/helpers@7.28.4", "", { "dependencies": { "@babel/template": "^7.27.2", "@babel/types": "^7.28.4" } }, "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w=="],
 
-    "@babel/parser": ["@babel/parser@7.27.5", "", { "dependencies": { "@babel/types": "^7.27.3" }, "bin": "./bin/babel-parser.js" }, "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg=="],
+    "@babel/parser": ["@babel/parser@7.28.5", "", { "dependencies": { "@babel/types": "^7.28.5" }, "bin": "./bin/babel-parser.js" }, "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ=="],
 
     "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="],
 
@@ -78,7 +79,7 @@
 
     "@babel/traverse": ["@babel/traverse@7.28.4", "", { "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", "@babel/types": "^7.28.4", "debug": "^4.3.1" } }, "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ=="],
 
-    "@babel/types": ["@babel/types@7.27.6", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q=="],
+    "@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="],
 
     "@capsizecss/unpack": ["@capsizecss/unpack@3.0.0", "", { "dependencies": { "fontkit": "^2.0.2" } }, "sha512-+ntATQe1AlL7nTOYjwjj6w3299CgRot48wL761TUGYpYgAou3AaONZazp0PKZyCyWhudWsjhq1nvRHOvbMzhTA=="],
 
 
     "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.43.0", "", { "os": "win32", "cpu": "x64" }, "sha512-SnGhLiE5rlK0ofq8kzuDkM0g7FN1s5VYY+YSMTibP7CqShxCQvqtNxTARS4xX4PFJfHjG0ZQYX9iGzI3FQh5Aw=="],
 
-    "@shikijs/core": ["@shikijs/core@3.12.2", "", { "dependencies": { "@shikijs/types": "3.12.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-L1Safnhra3tX/oJK5kYHaWmLEBJi1irASwewzY3taX5ibyXyMkkSDZlq01qigjryOBwrXSdFgTiZ3ryzSNeu7Q=="],
+    "@shikijs/core": ["@shikijs/core@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-8TOG6yG557q+fMsSVa8nkEDOZNTSxjbbR8l6lF2gyr6Np+jrPlslqDxQkN6rMXCECQ3isNPZAGszAfYoJOPGlg=="],
 
-    "@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.12.2", "", { "dependencies": { "@shikijs/types": "3.12.2", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-Nm3/azSsaVS7hk6EwtHEnTythjQfwvrO5tKqMlaH9TwG1P+PNaR8M0EAKZ+GaH2DFwvcr4iSfTveyxMIvXEHMw=="],
+    "@shikijs/engine-javascript": ["@shikijs/engine-javascript@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.3" } }, "sha512-ZedbOFpopibdLmvTz2sJPJgns8Xvyabe2QbmqMTz07kt1pTzfEvKZc5IqPVO/XFiEbbNyaOpjPBkkr1vlwS+qg=="],
 
-    "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.12.2", "", { "dependencies": { "@shikijs/types": "3.12.2", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-hozwnFHsLvujK4/CPVHNo3Bcg2EsnG8krI/ZQ2FlBlCRpPZW4XAEQmEwqegJsypsTAN9ehu2tEYe30lYKSZW/w=="],
+    "@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-HnqFsV11skAHvOArMZdLBZZApRSYS4LSztk2K3016Y9VCyZISnlYUYsL2hzlS7tPqKHvNqmI5JSUJZprXloMvA=="],
 
-    "@shikijs/langs": ["@shikijs/langs@3.12.2", "", { "dependencies": { "@shikijs/types": "3.12.2" } }, "sha512-bVx5PfuZHDSHoBal+KzJZGheFuyH4qwwcwG/n+MsWno5cTlKmaNtTsGzJpHYQ8YPbB5BdEdKU1rga5/6JGY8ww=="],
+    "@shikijs/langs": ["@shikijs/langs@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0" } }, "sha512-WpRvEFvkVvO65uKYW4Rzxs+IG0gToyM8SARQMtGGsH4GDMNZrr60qdggXrFOsdfOVssG/QQGEl3FnJ3EZ+8w8A=="],
 
-    "@shikijs/themes": ["@shikijs/themes@3.12.2", "", { "dependencies": { "@shikijs/types": "3.12.2" } }, "sha512-fTR3QAgnwYpfGczpIbzPjlRnxyONJOerguQv1iwpyQZ9QXX4qy/XFQqXlf17XTsorxnHoJGbH/LXBvwtqDsF5A=="],
+    "@shikijs/themes": ["@shikijs/themes@3.15.0", "", { "dependencies": { "@shikijs/types": "3.15.0" } }, "sha512-8ow2zWb1IDvCKjYb0KiLNrK4offFdkfNVPXb1OZykpLCzRU6j+efkY+Y7VQjNlNFXonSw+4AOdGYtmqykDbRiQ=="],
 
-    "@shikijs/types": ["@shikijs/types@3.12.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-K5UIBzxCyv0YoxN3LMrKB9zuhp1bV+LgewxuVwHdl4Gz5oePoUFrr9EfgJlGlDeXCU1b/yhdnXeuRvAnz8HN8Q=="],
+    "@shikijs/types": ["@shikijs/types@3.15.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-BnP+y/EQnhihgHy4oIAN+6FFtmfTekwOLsQbRw9hOKwqgNy8Bdsjq8B05oAt/ZgvIWWFrshV71ytOrlPfYjIJw=="],
 
     "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="],
 
 
     "@types/babel__traverse": ["@types/babel__traverse@7.20.7", "", { "dependencies": { "@babel/types": "^7.20.7" } }, "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng=="],
 
-    "@types/bun": ["@types/bun@1.3.0", "", { "dependencies": { "bun-types": "1.3.0" } }, "sha512-+lAGCYjXjip2qY375xX/scJeVRmZ5cY0wyHYyCYxNcdEXrQ4AOe3gACgd4iQ8ksOslJtW4VNxBJ8llUwc3a6AA=="],
+    "@types/bun": ["@types/bun@1.3.2", "", { "dependencies": { "bun-types": "1.3.2" } }, "sha512-t15P7k5UIgHKkxwnMNkJbWlh/617rkDGEdSsDbu+qNHTaz9SKf7aC8fiIlUdD5RPpH6GEkP0cK7WlvmrEBRtWg=="],
 
     "@types/d3-array": ["@types/d3-array@3.2.1", "", {}, "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg=="],
 
 
     "@types/node": ["@types/node@24.0.1", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-MX4Zioh39chHlDJbKmEgydJDS3tspMP/lnQC67G3SWsTnb9NeYVWOjkxpOSy4oMfPs4StcWHwBrvUb4ybfnuaw=="],
 
-    "@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="],
+    "@types/react": ["@types/react@19.2.5", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-keKxkZMqnDicuvFoJbzrhbtdLSPhj/rZThDlKWCDbgXmUg0rEUFtRssDXKYmtXluZlIqiC5VqkCgRwzuyLHKHw=="],
 
-    "@types/react-dom": ["@types/react-dom@19.2.2", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-9KQPoO6mZCi7jcIStSnlOWn2nEF3mNmyr3rIAsGnAbQKYbRLyqmeSc39EVgtxXVia+LMT8j3knZLAZAh+xLmrw=="],
+    "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
 
     "@types/sax": ["@types/sax@1.2.7", "", { "dependencies": { "@types/node": "*" } }, "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A=="],
 
 
     "astring": ["astring@1.9.0", "", { "bin": { "astring": "bin/astring" } }, "sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg=="],
 
-    "astro": ["astro@5.14.5", "", { "dependencies": { "@astrojs/compiler": "^2.12.2", "@astrojs/internal-helpers": "0.7.4", "@astrojs/markdown-remark": "6.3.8", "@astrojs/telemetry": "3.3.0", "@capsizecss/unpack": "^3.0.0", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.2.0", "acorn": "^8.15.0", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", "boxen": "8.0.1", "ci-info": "^4.3.0", "clsx": "^2.1.1", "common-ancestor-path": "^1.0.1", "cookie": "^1.0.2", "cssesc": "^3.0.0", "debug": "^4.4.1", "deterministic-object-hash": "^2.0.2", "devalue": "^5.3.2", "diff": "^5.2.0", "dlv": "^1.1.3", "dset": "^3.1.4", "es-module-lexer": "^1.7.0", "esbuild": "^0.25.0", "estree-walker": "^3.0.3", "flattie": "^1.1.1", "fontace": "~0.3.0", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.2.0", "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.0", "kleur": "^4.1.5", "magic-string": "^0.30.18", "magicast": "^0.3.5", "mrmime": "^2.0.1", "neotraverse": "^0.6.18", "p-limit": "^6.2.0", "p-queue": "^8.1.0", "package-manager-detector": "^1.3.0", "picomatch": "^4.0.3", "prompts": "^2.4.2", "rehype": "^13.0.2", "semver": "^7.7.2", "shiki": "^3.12.0", "smol-toml": "^1.4.2", "tinyexec": "^1.0.1", "tinyglobby": "^0.2.14", "tsconfck": "^3.1.6", "ultrahtml": "^1.6.0", "unifont": "~0.6.0", "unist-util-visit": "^5.0.0", "unstorage": "^1.17.0", "vfile": "^6.0.3", "vite": "^6.3.6", "vitefu": "^1.1.1", "xxhash-wasm": "^1.1.0", "yargs-parser": "^21.1.1", "yocto-spinner": "^0.2.3", "zod": "^3.25.76", "zod-to-json-schema": "^3.24.6", "zod-to-ts": "^1.2.0" }, "optionalDependencies": { "sharp": "^0.34.0" }, "bin": { "astro": "astro.js" } }, "sha512-EHt7y3+nHYyKzBats1AL3N4Pyrvqyr+zXBC7njUa9Tfe+gsiHlunaw+lXitTT/DDVwO2R/f/qVG7Xc6rl0b2KQ=="],
+    "astro": ["astro@5.15.8", "", { "dependencies": { "@astrojs/compiler": "^2.13.0", "@astrojs/internal-helpers": "0.7.4", "@astrojs/markdown-remark": "6.3.8", "@astrojs/telemetry": "3.3.0", "@capsizecss/unpack": "^3.0.0", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.3.0", "acorn": "^8.15.0", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", "boxen": "8.0.1", "ci-info": "^4.3.1", "clsx": "^2.1.1", "common-ancestor-path": "^1.0.1", "cookie": "^1.0.2", "cssesc": "^3.0.0", "debug": "^4.4.3", "deterministic-object-hash": "^2.0.2", "devalue": "^5.4.2", "diff": "^5.2.0", "dlv": "^1.1.3", "dset": "^3.1.4", "es-module-lexer": "^1.7.0", "esbuild": "^0.25.0", "estree-walker": "^3.0.3", "flattie": "^1.1.1", "fontace": "~0.3.1", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.2.0", "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.0", "magic-string": "^0.30.21", "magicast": "^0.5.1", "mrmime": "^2.0.1", "neotraverse": "^0.6.18", "p-limit": "^6.2.0", "p-queue": "^8.1.1", "package-manager-detector": "^1.5.0", "picocolors": "^1.1.1", "picomatch": "^4.0.3", "prompts": "^2.4.2", "rehype": "^13.0.2", "semver": "^7.7.3", "shiki": "^3.15.0", "smol-toml": "^1.4.2", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tsconfck": "^3.1.6", "ultrahtml": "^1.6.0", "unifont": "~0.6.0", "unist-util-visit": "^5.0.0", "unstorage": "^1.17.2", "vfile": "^6.0.3", "vite": "^6.4.1", "vitefu": "^1.1.1", "xxhash-wasm": "^1.1.0", "yargs-parser": "^21.1.1", "yocto-spinner": "^0.2.3", "zod": "^3.25.76", "zod-to-json-schema": "^3.24.6", "zod-to-ts": "^1.2.0" }, "optionalDependencies": { "sharp": "^0.34.0" }, "bin": { "astro": "astro.js" } }, "sha512-QiiRnNPdxCcAGO2UlO07o+QeGgRfEC5Dlm0x35WPB/ixFK1T2bsNB6KaXri70cVkYY1GYgoRtrWv3HCR26o9aw=="],
 
     "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="],
 
 
     "browserslist": ["browserslist@4.25.1", "", { "dependencies": { "caniuse-lite": "^1.0.30001726", "electron-to-chromium": "^1.5.173", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw=="],
 
-    "bun-types": ["bun-types@1.3.0", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-u8X0thhx+yJ0KmkxuEo9HAtdfgCBaM/aI9K90VQcQioAmkVp3SG3FkwWGibUFz3WdXAdcsqOcbU40lK7tbHdkQ=="],
+    "bun-types": ["bun-types@1.3.2", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-i/Gln4tbzKNuxP70OWhJRZz1MRfvqExowP7U6JKoI8cntFrtxg7RJK3jvz7wQW54UuvNC8tbKHHri5fy74FVqg=="],
 
     "camelcase": ["camelcase@8.0.0", "", {}, "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA=="],
 
 
     "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="],
 
-    "ci-info": ["ci-info@4.3.0", "", {}, "sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ=="],
+    "ci-info": ["ci-info@4.3.1", "", {}, "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA=="],
 
     "cli-boxes": ["cli-boxes@3.0.0", "", {}, "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g=="],
 
 
     "d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="],
 
-    "debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
+    "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
 
     "decimal.js-light": ["decimal.js-light@2.5.1", "", {}, "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="],
 
 
     "deterministic-object-hash": ["deterministic-object-hash@2.0.2", "", { "dependencies": { "base-64": "^1.0.0" } }, "sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ=="],
 
-    "devalue": ["devalue@5.3.2", "", {}, "sha512-UDsjUbpQn9kvm68slnrs+mfxwFkIflOhkanmyabZ8zOYk8SMEIbJ3TK+88g70hSIeytu4y18f0z/hYHMTrXIWw=="],
+    "devalue": ["devalue@5.5.0", "", {}, "sha512-69sM5yrHfFLJt0AZ9QqZXGCPfJ7fQjvpln3Rq5+PS03LD32Ost1Q9N+eEnaQwGRIriKkMImXD56ocjQmfjbV3w=="],
 
     "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="],
 
 
     "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
 
-    "fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
+    "fast-xml-parser": ["fast-xml-parser@5.3.2", "", { "dependencies": { "strnum": "^2.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-n8v8b6p4Z1sMgqRmqLJm3awW4NX7NkaKPfb3uJIBTSH7Pdvufi3PQ3/lJLQrvxcMYl7JI2jnDO90siPEpD8JBA=="],
 
     "fdir": ["fdir@6.4.6", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w=="],
 
 
     "flattie": ["flattie@1.1.1", "", {}, "sha512-9UbaD6XdAL97+k/n+N7JwX46K/M6Zc6KcFYskrYL8wbBV/Uyk0CTAMY0VT+qiK5PM7AIc9aTWYtq65U7T+aCNQ=="],
 
-    "fontace": ["fontace@0.3.0", "", { "dependencies": { "@types/fontkit": "^2.0.8", "fontkit": "^2.0.4" } }, "sha512-czoqATrcnxgWb/nAkfyIrRp6Q8biYj7nGnL6zfhTcX+JKKpWHFBnb8uNMw/kZr7u++3Y3wYSYoZgHkCcsuBpBg=="],
+    "fontace": ["fontace@0.3.1", "", { "dependencies": { "@types/fontkit": "^2.0.8", "fontkit": "^2.0.4" } }, "sha512-9f5g4feWT1jWT8+SbL85aLIRLIXUaDygaM2xPXRmzPYxrOMNok79Lr3FGJoKVNKibE0WCunNiEVG2mwuE+2qEg=="],
 
     "fontkit": ["fontkit@2.0.4", "", { "dependencies": { "@swc/helpers": "^0.5.12", "brotli": "^1.3.2", "clone": "^2.1.2", "dfa": "^1.2.0", "fast-deep-equal": "^3.1.3", "restructure": "^3.0.0", "tiny-inflate": "^1.0.3", "unicode-properties": "^1.4.0", "unicode-trie": "^2.0.0" } }, "sha512-syetQadaUEDNdxdugga9CpEYVaQIxOwk7GlwZWWZ19//qW4zE5bknOKeMBDYAASwnpaSHKJITRLMF9m1fp3s6g=="],
 
 
     "is-wsl": ["is-wsl@3.1.0", "", { "dependencies": { "is-inside-container": "^1.0.0" } }, "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw=="],
 
-    "jiti": ["jiti@2.4.2", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A=="],
-
     "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
 
     "js-yaml": ["js-yaml@4.1.0", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="],
 
     "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="],
 
-    "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="],
-
-    "lightningcss": ["lightningcss@1.30.1", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-darwin-arm64": "1.30.1", "lightningcss-darwin-x64": "1.30.1", "lightningcss-freebsd-x64": "1.30.1", "lightningcss-linux-arm-gnueabihf": "1.30.1", "lightningcss-linux-arm64-gnu": "1.30.1", "lightningcss-linux-arm64-musl": "1.30.1", "lightningcss-linux-x64-gnu": "1.30.1", "lightningcss-linux-x64-musl": "1.30.1", "lightningcss-win32-arm64-msvc": "1.30.1", "lightningcss-win32-x64-msvc": "1.30.1" } }, "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg=="],
-
-    "lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.30.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ=="],
-
-    "lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.30.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA=="],
-
-    "lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.30.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig=="],
-
-    "lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.30.1", "", { "os": "linux", "cpu": "arm" }, "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q=="],
-
-    "lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.30.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw=="],
-
-    "lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.30.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ=="],
-
-    "lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.30.1", "", { "os": "linux", "cpu": "x64" }, "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw=="],
-
-    "lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.30.1", "", { "os": "linux", "cpu": "x64" }, "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ=="],
-
-    "lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.30.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA=="],
-
-    "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.1", "", { "os": "win32", "cpu": "x64" }, "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg=="],
+    "kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
 
     "linebreak": ["linebreak@1.1.0", "", { "dependencies": { "base64-js": "0.0.8", "unicode-trie": "^2.0.0" } }, "sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ=="],
 
 
     "lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
 
-    "magic-string": ["magic-string@0.30.19", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw=="],
+    "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
 
-    "magicast": ["magicast@0.3.5", "", { "dependencies": { "@babel/parser": "^7.25.4", "@babel/types": "^7.25.4", "source-map-js": "^1.2.0" } }, "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ=="],
+    "magicast": ["magicast@0.5.1", "", { "dependencies": { "@babel/parser": "^7.28.5", "@babel/types": "^7.28.5", "source-map-js": "^1.2.1" } }, "sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw=="],
 
     "markdown-extensions": ["markdown-extensions@2.0.0", "", {}, "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q=="],
 
 
     "p-limit": ["p-limit@6.2.0", "", { "dependencies": { "yocto-queue": "^1.1.1" } }, "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA=="],
 
-    "p-queue": ["p-queue@8.1.0", "", { "dependencies": { "eventemitter3": "^5.0.1", "p-timeout": "^6.1.2" } }, "sha512-mxLDbbGIBEXTJL0zEx8JIylaj3xQ7Z/7eEVjcF9fJX4DBiH9oqe+oahYnlKKxm0Ci9TlWTyhSHgygxMxjIB2jw=="],
+    "p-queue": ["p-queue@8.1.1", "", { "dependencies": { "eventemitter3": "^5.0.1", "p-timeout": "^6.1.2" } }, "sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ=="],
 
     "p-timeout": ["p-timeout@6.1.4", "", {}, "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg=="],
 
-    "package-manager-detector": ["package-manager-detector@1.3.0", "", {}, "sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ=="],
+    "package-manager-detector": ["package-manager-detector@1.5.0", "", {}, "sha512-uBj69dVlYe/+wxj8JOpr97XfsxH/eumMt6HqjNTmJDf/6NO9s+0uxeOneIz3AsPt2m6y9PqzDzd3ATcU17MNfw=="],
 
     "pako": ["pako@0.2.9", "", {}, "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA=="],
 
 
     "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="],
 
-    "recharts": ["recharts@3.2.1", "", { "dependencies": { "@reduxjs/toolkit": "1.x.x || 2.x.x", "clsx": "^2.1.1", "decimal.js-light": "^2.5.1", "es-toolkit": "^1.39.3", "eventemitter3": "^5.0.1", "immer": "^10.1.1", "react-redux": "8.x.x || 9.x.x", "reselect": "5.1.1", "tiny-invariant": "^1.3.3", "use-sync-external-store": "^1.2.2", "victory-vendor": "^37.0.2" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-0JKwHRiFZdmLq/6nmilxEZl3pqb4T+aKkOkOi/ZISRZwfBhVMgInxzlYU9D4KnCH3KINScLy68m/OvMXoYGZUw=="],
+    "recharts": ["recharts@3.4.1", "", { "dependencies": { "@reduxjs/toolkit": "1.x.x || 2.x.x", "clsx": "^2.1.1", "decimal.js-light": "^2.5.1", "es-toolkit": "^1.39.3", "eventemitter3": "^5.0.1", "immer": "^10.1.1", "react-redux": "8.x.x || 9.x.x", "reselect": "5.1.1", "tiny-invariant": "^1.3.3", "use-sync-external-store": "^1.2.2", "victory-vendor": "^37.0.2" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-35kYg6JoOgwq8sE4rhYkVWwa6aAIgOtT+Ob0gitnShjwUwZmhrmy7Jco/5kJNF4PnLXgt9Hwq+geEMS+WrjU1g=="],
 
     "recma-build-jsx": ["recma-build-jsx@1.0.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-util-build-jsx": "^3.0.0", "vfile": "^6.0.0" } }, "sha512-8GtdyqaBcDfva+GUKDr3nev3VpKAhup1+RvkMvUxURHpW7QyIvk9F5wz7Vzo06CEMSilw6uArgRqhpiUcWp8ew=="],
 
 
     "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
 
-    "semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
+    "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
 
     "sharp": ["sharp@0.34.3", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.4", "semver": "^7.7.2" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.3", "@img/sharp-darwin-x64": "0.34.3", "@img/sharp-libvips-darwin-arm64": "1.2.0", "@img/sharp-libvips-darwin-x64": "1.2.0", "@img/sharp-libvips-linux-arm": "1.2.0", "@img/sharp-libvips-linux-arm64": "1.2.0", "@img/sharp-libvips-linux-ppc64": "1.2.0", "@img/sharp-libvips-linux-s390x": "1.2.0", "@img/sharp-libvips-linux-x64": "1.2.0", "@img/sharp-libvips-linuxmusl-arm64": "1.2.0", "@img/sharp-libvips-linuxmusl-x64": "1.2.0", "@img/sharp-linux-arm": "0.34.3", "@img/sharp-linux-arm64": "0.34.3", "@img/sharp-linux-ppc64": "0.34.3", "@img/sharp-linux-s390x": "0.34.3", "@img/sharp-linux-x64": "0.34.3", "@img/sharp-linuxmusl-arm64": "0.34.3", "@img/sharp-linuxmusl-x64": "0.34.3", "@img/sharp-wasm32": "0.34.3", "@img/sharp-win32-arm64": "0.34.3", "@img/sharp-win32-ia32": "0.34.3", "@img/sharp-win32-x64": "0.34.3" } }, "sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg=="],
 
-    "shiki": ["shiki@3.12.2", "", { "dependencies": { "@shikijs/core": "3.12.2", "@shikijs/engine-javascript": "3.12.2", "@shikijs/engine-oniguruma": "3.12.2", "@shikijs/langs": "3.12.2", "@shikijs/themes": "3.12.2", "@shikijs/types": "3.12.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-uIrKI+f9IPz1zDT+GMz+0RjzKJiijVr6WDWm9Pe3NNY6QigKCfifCEv9v9R2mDASKKjzjQ2QpFLcxaR3iHSnMA=="],
+    "shiki": ["shiki@3.15.0", "", { "dependencies": { "@shikijs/core": "3.15.0", "@shikijs/engine-javascript": "3.15.0", "@shikijs/engine-oniguruma": "3.15.0", "@shikijs/langs": "3.15.0", "@shikijs/themes": "3.15.0", "@shikijs/types": "3.15.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-kLdkY6iV3dYbtPwS9KXU7mjfmDm25f5m0IPNFnaXO7TBPcvbUOY72PYXSuSqDzwp+vlH/d7MXpHlKO/x+QoLXw=="],
 
     "simple-swizzle": ["simple-swizzle@0.2.2", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg=="],
 
 
     "tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="],
 
-    "tinyexec": ["tinyexec@1.0.1", "", {}, "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw=="],
+    "tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="],
 
-    "tinyglobby": ["tinyglobby@0.2.14", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ=="],
+    "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
 
     "trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="],
 
 
     "unist-util-visit-parents": ["unist-util-visit-parents@6.0.1", "", { "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" } }, "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw=="],
 
-    "unstorage": ["unstorage@1.17.1", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^4.0.3", "destr": "^2.0.5", "h3": "^1.15.4", "lru-cache": "^10.4.3", "node-fetch-native": "^1.6.7", "ofetch": "^1.4.1", "ufo": "^1.6.1" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6.0.3 || ^7.0.0", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1.0.1", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-KKGwRTT0iVBCErKemkJCLs7JdxNVfqTPc/85ae1XES0+bsHbc/sFBfVi5kJp156cc51BHinIH2l3k0EZ24vOBQ=="],
+    "unstorage": ["unstorage@1.17.2", "", { "dependencies": { "anymatch": "^3.1.3", "chokidar": "^4.0.3", "destr": "^2.0.5", "h3": "^1.15.4", "lru-cache": "^10.4.3", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.0", "ufo": "^1.6.1" }, "peerDependencies": { "@azure/app-configuration": "^1.8.0", "@azure/cosmos": "^4.2.0", "@azure/data-tables": "^13.3.0", "@azure/identity": "^4.6.0", "@azure/keyvault-secrets": "^4.9.0", "@azure/storage-blob": "^12.26.0", "@capacitor/preferences": "^6.0.3 || ^7.0.0", "@deno/kv": ">=0.9.0", "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", "@planetscale/database": "^1.19.0", "@upstash/redis": "^1.34.3", "@vercel/blob": ">=0.27.1", "@vercel/functions": "^2.2.12 || ^3.0.0", "@vercel/kv": "^1.0.1", "aws4fetch": "^1.0.20", "db0": ">=0.2.1", "idb-keyval": "^6.2.1", "ioredis": "^5.4.2", "uploadthing": "^7.4.4" }, "optionalPeers": ["@azure/app-configuration", "@azure/cosmos", "@azure/data-tables", "@azure/identity", "@azure/keyvault-secrets", "@azure/storage-blob", "@capacitor/preferences", "@deno/kv", "@netlify/blobs", "@planetscale/database", "@upstash/redis", "@vercel/blob", "@vercel/functions", "@vercel/kv", "aws4fetch", "db0", "idb-keyval", "ioredis", "uploadthing"] }, "sha512-cKEsD6iBWJgOMJ6vW1ID/SYuqNf8oN4yqRk8OYqaVQ3nnkJXOT1PSpaMh2QfzLs78UN5kSNRD2c/mgjT8tX7+w=="],
 
     "update-browserslist-db": ["update-browserslist-db@1.1.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw=="],
 
 
     "victory-vendor": ["victory-vendor@37.3.6", "", { "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", "@types/d3-interpolate": "^3.0.1", "@types/d3-scale": "^4.0.2", "@types/d3-shape": "^3.1.0", "@types/d3-time": "^3.0.0", "@types/d3-timer": "^3.0.0", "d3-array": "^3.1.6", "d3-ease": "^3.0.1", "d3-interpolate": "^3.0.1", "d3-scale": "^4.0.2", "d3-shape": "^3.1.0", "d3-time": "^3.0.0", "d3-timer": "^3.0.1" } }, "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ=="],
 
-    "vite": ["vite@6.3.6", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA=="],
+    "vite": ["vite@6.4.1", "", { "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", "tinyglobby": "^0.2.13" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g=="],
 
     "vitefu": ["vitefu@1.1.1", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" }, "optionalPeers": ["vite"] }, "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ=="],
 
 
     "@astrojs/telemetry/ci-info": ["ci-info@4.2.0", "", {}, "sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg=="],
 
+    "@astrojs/telemetry/debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
+
+    "@babel/code-frame/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="],
+
     "@babel/core/@babel/parser": ["@babel/parser@7.28.4", "", { "dependencies": { "@babel/types": "^7.28.4" }, "bin": "./bin/babel-parser.js" }, "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg=="],
 
     "@babel/core/@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="],
 
+    "@babel/core/debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
+
     "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="],
 
     "@babel/generator/@babel/parser": ["@babel/parser@7.28.4", "", { "dependencies": { "@babel/types": "^7.28.4" }, "bin": "./bin/babel-parser.js" }, "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg=="],
 
     "@babel/helper-module-imports/@babel/types": ["@babel/types@7.27.7", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-8OLQgDScAOHXnAz2cV+RfzzNMipuLVBz2biuAJFMV9bfkNf393je3VM8CLkjQodW5+iWsSJdSgSWT6rsZoXHPw=="],
 
+    "@babel/helper-module-transforms/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="],
+
     "@babel/helpers/@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="],
 
     "@babel/template/@babel/parser": ["@babel/parser@7.27.7", "", { "dependencies": { "@babel/types": "^7.27.7" }, "bin": "./bin/babel-parser.js" }, "sha512-qnzXzDXdr/po3bOTbTIQZ7+TxNKxpkN5IifVLXS+r7qwynkZfPyjZfE7hCXbo7IoO9TNcSyibgONsf2HauUd3Q=="],
 
     "@babel/traverse/@babel/types": ["@babel/types@7.28.4", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" } }, "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q=="],
 
+    "@babel/traverse/debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
+
     "@jridgewell/gen-mapping/@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="],
 
     "@jridgewell/trace-mapping/@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.0", "", {}, "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ=="],
 
     "hast-util-to-parse5/property-information": ["property-information@6.5.0", "", {}, "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig=="],
 
+    "micromark/debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
+
     "ofetch/node-fetch-native": ["node-fetch-native@1.6.6", "", {}, "sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ=="],
 
     "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
 
-    "prompts/kleur": ["kleur@3.0.3", "", {}, "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="],
-
     "rollup/@types/estree": ["@types/estree@1.0.7", "", {}, "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ=="],
 
+    "sharp/semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
+
     "sitemap/@types/node": ["@types/node@17.0.45", "", {}, "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw=="],
 
-    "tinyglobby/picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="],
+    "tinyglobby/fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
 
     "unicode-properties/base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
 
-    "vite/picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="],
+    "unstorage/ofetch": ["ofetch@1.5.1", "", { "dependencies": { "destr": "^2.0.5", "node-fetch-native": "^1.6.7", "ufo": "^1.6.1" } }, "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA=="],
+
+    "vite/tinyglobby": ["tinyglobby@0.2.14", "", { "dependencies": { "fdir": "^6.4.4", "picomatch": "^4.0.2" } }, "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ=="],
 
     "@astrojs/markdown-remark/shiki/@shikijs/core": ["@shikijs/core@3.13.0", "", { "dependencies": { "@shikijs/types": "3.13.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-3P8rGsg2Eh2qIHekwuQjzWhKI4jV97PhvYjYUzGqjvJfqdQPz+nMlfWahU24GZAyW1FxFI1sYjyhfh5CoLmIUA=="],
 
 
     "@astrojs/markdown-remark/shiki/@shikijs/types": ["@shikijs/types@3.13.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-oM9P+NCFri/mmQ8LoFGVfVyemm5Hi27330zuOBp0annwJdKH1kOLndw3zCtAVDehPLg9fKqoEx3Ht/wNZxolfw=="],
 
+    "@babel/core/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="],
+
+    "@babel/generator/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="],
+
     "@babel/helper-module-imports/@babel/traverse/@babel/generator": ["@babel/generator@7.27.5", "", { "dependencies": { "@babel/parser": "^7.27.5", "@babel/types": "^7.27.3", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" } }, "sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw=="],
 
     "@babel/helper-module-imports/@babel/traverse/@babel/parser": ["@babel/parser@7.27.7", "", { "dependencies": { "@babel/types": "^7.27.7" }, "bin": "./bin/babel-parser.js" }, "sha512-qnzXzDXdr/po3bOTbTIQZ7+TxNKxpkN5IifVLXS+r7qwynkZfPyjZfE7hCXbo7IoO9TNcSyibgONsf2HauUd3Q=="],
 
+    "@babel/helper-module-imports/@babel/traverse/debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="],
+
+    "@babel/helper-module-imports/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="],
+
+    "@babel/helpers/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="],
+
+    "@babel/template/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="],
+
+    "@babel/traverse/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="],
+
+    "@types/babel__core/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="],
+
+    "@types/babel__generator/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="],
+
+    "@types/babel__template/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="],
+
+    "@types/babel__traverse/@babel/types/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.27.1", "", {}, "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow=="],
+
     "ansi-align/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
 
     "ansi-align/string-width/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
 
+    "vite/tinyglobby/picomatch": ["picomatch@4.0.2", "", {}, "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg=="],
+
     "ansi-align/string-width/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
   }
 }
index e298cb835be78b28c60ab5833d0c62e9193467d1..adbe3e47cdca893be0a8bf4495c54a461d591ec4 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: A Complete Unknown
 date: 2025-06-04
 modified: 2025-06-04
 rating: 3
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/a-complete-unknown/
 ---
index e832f36b41c3a975c7f9439bf68015ea56831d8c..0c479637d23345404b25cabc7247a9333294b7cb 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: Bugonia
 date: 2025-10-30
 modified: 2025-11-01
 rating: 3
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/bugonia/
 ---
index 768ca9d53a7f6e1fd9f2d9ea227b89aa12248885..adaf05709beece32b18fee611b6b7cb5640bee60 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: Burning
 date: 2025-02-28
 modified: 2025-03-02
 rating: 3
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/burning-2018/
 ---
index 8d020f25a59be8a4a5d4f58258a91cdd2b746751..bbc926c478d692e4dfb853e79b7fd5bd3db474db 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: Caught Stealing
 date: 2025-09-12
 modified: 2025-09-13
 rating: 2
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/caught-stealing/
 ---
index 8403793ffe46a83db7d2d48ff712c9638c43e6ed..bd4ee67dc0317d9555a03d786f9eab0f99f39678 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: Challengers
 date: 2024-12-24
 modified: 2024-12-26
 rating: 3
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/challengers/
 ---
index 197ba305680b9ab520ce9ddef234019965f40a69..656de8d5b9f817939c3f9e0d5d6d0081211bac38 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: Conclave
 date: 2025-03-02
 modified: 2025-03-18
 rating: 4
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/conclave/
 ---
index e8ada828253b09414413031d74d89445cf8b7693..56b4c0e7ef5c44674d98cf702d4a53beaff095cc 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: Death Becomes Her
 date: 2025-10-02
 modified: 2025-10-07
 rating: 3
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/death-becomes-her/
 ---
index 291488add3b781b43a7cff51e7df336a5979afcd..970c35b25a4233f7c54a691f560d57e9fa298e97 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: "Den of Thieves: Pantera"
 date: 2025-10-18
 modified: 2025-10-19
 rating: 1
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/den-of-thieves-2-pantera/
 ---
index 04344fa525dad6d8ba347edd575bf5b1d93119e2..8efb01dd27c6986b5bddeba8d07916c19327dcc6 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: "F1: The Movie"
 date: 2025-10-16
 modified: 2025-10-17
 rating: 2
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/f1/
 ---
index e5254f445516bd04e08c5f06c68a5c528e71f751..f840145e633f26df84c4dab7568a80f934f5e361 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: Fallen Angels
 date: 2025-08-02
 modified: 2025-10-24
 rating: 4
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/fallen-angels/
 ---
index 70d6ba7f9b9909eac3bc3b5b35c264f02225a5f8..e74e414aa5d70a525cd6df5c97e2c4eed14132d2 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: The Hunchback of Notre Dame
 date: 2025-03-04
 modified: 2025-03-22
 rating: 4
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/the-hunchback-of-notre-dame-1996/
 ---
index 960e58079cb7c2dcca4fddfeed3bca2ff8031887..b405b20d472f7a0262d075048a2736dab97ad92f 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: It's What's Inside
 date: 2025-03-01
 modified: 2025-03-02
 rating: 2
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/its-whats-inside/
 ---
index d519a40d178f8816300265b787bf60f01cb9aceb..dc616e4dd39e43970eabbe9dd3af0bc71ac9ae0b 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: Jurassic Park
 date: 2025-09-10
 modified: 2025-09-13
 rating: 5
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/jurassic-park/
 ---
index e0ec98c0fb1b30fadc639dd836f5cb19e84accb0..1280894231aa27b9989b1d956d0924faae243607 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: Materialists
 date: 2025-08-14
 modified: 2025-08-15
 rating: 2
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/materialists/
 ---
index b3de00e732ca94733e380e866bf03c69297fac48..09030112e439cd7f678a451ecdc67ff964755333 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: Nosferatu
 date: 2025-09-09
 modified: 2025-09-13
 rating: 4
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/nosferatu-2024/
 ---
index 286930c1219376230d181c8ec684f5c476f7f4d3..c42aa116c23f58f870d8f197eb9782aa23dc4bf3 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: One Battle After Another
 date: 2025-10-01
 modified: 2025-10-04
 rating: 4
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/one-battle-after-another/
 ---
index 272291f5eeb5134db370fbeb96e796fcc7107390..75048e3159c96c556ce34dfb22146a551df4625f 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: Perfect Days
 date: 2025-02-15
 modified: 2025-02-15
 rating: 4
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/perfect-days-2023/
 ---
index 453e5e178ed69dac0d672ffaf85f6d5ac1b9c12b..d8a3f676f501ef758795907e4517eb6015f7d3d0 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: Problemista
 date: 2025-11-04
 modified: 2025-11-06
 rating: 3
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/problemista/
 ---
index d3d97092b3cd9eb3a5de57614ab1084219cf5673..fcf368022a4477b8d5b57010bfd4934ed63e9467 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: Sinners
 date: 2025-05-02
 modified: 2025-05-02
 rating: 4
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/sinners-2025/
 ---
index ae790166fc8eaa44d4bcdb59635ac0014555fad8..ab41eeab01fdb30d47fdb764cabc4104b8acda87 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: "Star Wars: Episode III - Revenge of the Sith"
 date: 2025-09-05
 modified: 2025-09-07
 rating: 3
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/star-wars-episode-iii-revenge-of-the-sith/
 ---
index 7dabf65b96dd9181707ba78116a0f647e74aa894..54aa77814bec8805b60aa5194bbfdfa301248fe6 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: Subservience
 date: 2024-12-25
 modified: 2024-12-26
 rating: 2
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/subservience-2024/
 ---
index 63c4a1e927608167e47c28f2afa8d78e910a3e39..17b5b3e78cdf7cf7796c0a40b4fb82838a8f0b7f 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: Superman
 date: 2025-10-04
 modified: 2025-10-04
 rating: 3
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/superman-2025/
 ---
index 8917fd49f5469b42e9bb550f2cda960865532df4..4fc5620ca58d38269c81d7a3bfc3c972fc8e1c8d 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: The Apprentice
 date: 2025-09-06
 modified: 2025-09-07
 rating: 3
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/the-apprentice-2024/
 ---
index fb823dc9dacf4158ec7144ee4c55c3fa53becfcc..1cf6c95c8a58339b8ff22cd535147b95b79f6457 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: The Boy and the Heron
 date: 2024-12-21
 modified: 2024-12-23
 rating: 5
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/the-boy-and-the-heron/
 ---
index 9221e2552637c1c22eb8372659c9da28d271a549..8351233fe5734d087c44be4b476541b419a498eb 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: Warfare
 date: 2025-04-11
 modified: 2025-04-11
 rating: 4
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/warfare/
 ---
index daf3c37809ae02130115ac45d91be4de0e054bf2..baec4b33c1195ae267a1c3b12df818d68e5efeb2 100644 (file)
@@ -1,10 +1,9 @@
 ---
+type: movie
 title: Wicked
 date: 2024-11-29
 modified: 2025-06-04
 rating: 4
-tags:
-- movie
 posse:
   Letterboxd: https://letterboxd.com/cotsuka/film/wicked-2024/
 ---
diff --git a/data/metadata.json b/data/metadata.json
deleted file mode 100644 (file)
index 1ade3c7..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-{
-    "title": "Cameron Otsuka",
-    "subtitle": "The collection of Cameron's thoughts.",
-    "base": "https://cameron.otsuka.systems",
-    "language": "en",
-    "author": {
-        "name": "Cameron Otsuka",
-        "email": "cameron@otsuka.haus"
-    },
-    "navMenu": [
-        { "title": "Articles", "url": "/articles" },
-        { "title": "Links", "url": "/links" },
-        { "title": "Reviews", "url": "/reviews" }
-    ],
-    "contributions": [
-        {
-            "title": "Git",
-            "url": "https://git.otsuka.systems"
-        },
-        {
-            "title": "Arch User Repository",
-            "url": "https://aur.archlinux.org/packages?O=0&SeB=M&K=cotsuka&outdated=&SB=p&SO=d&PP=50&submit=Go"
-        },
-        {
-            "title": "ArchWiki",
-            "url": "https://wiki.archlinux.org/title/Special:Contributions/Cotsuka"
-        },
-        {
-            "title": "GitHub",
-            "url": "https://github.com/search?q=author%3Acotsuka&type=pullrequests"
-        },
-        {
-            "title": "Wikipedia",
-            "url": "https://en.wikipedia.org/wiki/Special:Contributions/Cotsuka"
-        }
-    ],
-    "socials": {
-        "x": {
-            "title": "𝕏",
-            "url": "https://x.com/CameronOtsuka",
-            "username": "@CameronOtsuka"
-        },
-        "linkedin": {
-            "title": "LinkedIn",
-            "url": "https://www.linkedin.com/in/cotsuka",
-            "username": "cotsuka"
-        },
-        "github": {
-            "title": "GitHub",
-            "url": "https://github.com/cotsuka",
-            "username": "cotsuka"
-        },
-        "activitypub": {
-            "title": "ActivityPub",
-            "url": "https://social.otsuka.systems/@cameron",
-            "username": "@cameron@otsuka.systems"
-        },
-        "nostr": {
-            "title": "Nostr",
-            "url": "https://primal.net/profile/npub1hzssq7wewjztvglpdvku92htx3sv2x5r9ycvqhvl9xrtt5fn629s3np693",
-            "username": "cameron@otsuka.systems"
-        }
-    }
-}
\ No newline at end of file
index 19cd3293249ece66588073fbe452a9d52b40d1e3..964799b75e8c7a3cbcc8f7e3045601183d0cedbf 100644 (file)
@@ -1,7 +1,7 @@
 {
   "name": "cotsuka.github.io",
   "description": "The collection of Cameron's thoughts.",
-  "version": "2.0.0",
+  "version": "2.1.0",
   "type": "module",
   "scripts": {
     "dev": "astro dev",
   "license": "MIT",
   "homepage": "https://github.com/cotsuka/cotsuka.github.io",
   "dependencies": {
-    "@astrojs/mdx": "4.3.7",
-    "@astrojs/react": "4.4.0",
-    "@astrojs/rss": "^4.0.12",
+    "@astrojs/mdx": "4.3.10",
+    "@astrojs/react": "4.4.2",
+    "@astrojs/rss": "4.0.13",
     "@astrojs/sitemap": "3.6.0",
     "@fontsource-variable/public-sans": "^5.2.7",
     "@fontsource-variable/source-code-pro": "^5.2.7",
-    "@types/react": "^19.2.2",
-    "@types/react-dom": "^19.2.2",
+    "@types/react": "^19.2.5",
+    "@types/react-dom": "^19.2.3",
     "@vercel/og": "^0.6.8",
-    "astro": "5.14.5",
+    "astro": "5.15.8",
     "react": "^19.2.0",
     "react-dom": "^19.2.0",
-    "recharts": "^3.2.1"
+    "recharts": "^3.4.1"
   },
   "devDependencies": {
-    "@types/bun": "^1.3.0"
+    "@types/bun": "^1.3.2"
   }
 }
\ No newline at end of file
index 5b9c004141567f5a4d2f308364da61517d61a6a9..728b4f0cabc52056291f7fa757ce5430e58061cc 100644 (file)
@@ -1,5 +1,5 @@
 ---
-import SiteMetadata from '@data/metadata.json';
+import { siteAuthor, socials } from '@utils/globals.ts';
 
 const currentYear = new Date().getFullYear();
 ---
@@ -7,13 +7,13 @@ const currentYear = new Date().getFullYear();
     <hr />
     <address>
         <menu>
-            {Object.keys(SiteMetadata.socials).map((social) => (
-                <li><a href={SiteMetadata.socials[social].url} rel="me">{SiteMetadata.socials[social].title}</a></li>
+            {Object.keys(socials).map((platform) => (
+                <li><a href={socials[platform].url} rel="me">{socials[platform].title}</a></li>
             ))}
         </menu>
     </address>
     <p>
-        &copy; {currentYear} {SiteMetadata.author.name}.<br>
+        &copy; {currentYear} {siteAuthor.name}.<br>
         All views my own. Not financial advice. Links, citations, and other references are not endorsements. Content is licensed under <a href="https://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a>.
     </p>
 </footer>
index 563116c01641edea6afd9c6bf94ac99ae610c0d2..dc1efe0f9c731e5cf5f7abf295f558b7b6a409b9 100644 (file)
@@ -1,5 +1,5 @@
 ---
-import SiteMetadata from '@data/metadata.json';
+import { siteAuthor } from '@utils/globals.ts';
 
 interface Props {
     publishedTime: string
@@ -12,7 +12,7 @@ const { publishedTime, modifiedTime, tags = [] } = Astro.props;
 <meta property="og:type" content="article" />
 <meta property="article:published_time" content={publishedTime} />
 <meta property="article:modified_time" content={modifiedTime} />
-<meta property="article:author" content={SiteMetadata.author.name} />
+<meta property="article:author" content={siteAuthor.name} />
 {tags.map((tag) => (
     <meta property="article:tag" content={tag} />
 ))}
index 4e6480dfc076fab0097aa1fa8558e0e40eb5207f..e469334e0820a5fbbc3aa5216bd2f1b12094aa87 100644 (file)
@@ -1,7 +1,7 @@
 ---
 import { getImage } from 'astro:assets';
+import { siteAuthor, siteTitle, socials } from '@utils/globals.ts';
 import FavIcon from '@assets/favicon.ico';
-import SiteMetadata from '@data/metadata.json';
 
 interface Props {
     title: string
@@ -22,15 +22,14 @@ const { title, description } = Astro.props;
 <link rel="icon" type="image/x-icon" href={favIcon.src} />
 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 <meta name="color-scheme" content="light dark" />
-<!-- <meta http-equiv="Content-Security-Policy" content="default-src 'self'; style-src 'self' 'unsafe-inline'; frame-src youtube.com www.youtube.com youtube-noocookie.com www.youtube-nocookie.com" /> -->
-<meta name="title" property="og:title" content={`${title} | ${SiteMetadata.title}`} />
+<meta name="title" property="og:title" content={`${title} | ${siteTitle}`} />
 <meta name="description" property="og:description" content={description} />
-<meta name="author" content={SiteMetadata.author.name} />
+<meta name="author" content={siteAuthor.name} />
 <meta name="generator" content={Astro.generator} />
-<meta name="fediverse:creator" content={SiteMetadata.socials.activitypub.username} />
+<meta name="fediverse:creator" content={socials.activitypub.username} />
 <meta name="twitter:card" content="summary_large_image" />
-<meta name="twitter:creator" content={SiteMetadata.socials.x.username} />
-<meta name="twitter:title" content={`${title} | ${SiteMetadata.title}`} />
+<meta name="twitter:creator" content={socials.x.username} />
+<meta name="twitter:title" content={`${title} | ${siteTitle}`} />
 <meta name="twitter:description" content={description} />
 <meta name="twitter:image" property="og:image" content={new URL("opengraph.png", canonicalURL)}  />
 <meta property="og:image:type" content="image/png" />
@@ -38,9 +37,9 @@ const { title, description } = Astro.props;
 <meta property="og:image:height" content="630" />
 <meta property="og:locale" content="en_US" />
 <meta property="og:url" content={canonicalURL} />
-<meta property="og:site_name" content={`${title} | ${SiteMetadata.title}`} />
+<meta property="og:site_name" content={`${title} | ${siteTitle}`} />
 <meta property="og:updated_time" content={new Date().toISOString()} />
-<title>{`${title} | ${SiteMetadata.title}`}</title>
+<title>{`${title} | ${siteTitle}`}</title>
 <link rel="canonical" href={canonicalURL} />
 <link rel="sitemap" href={new URL("sitemap-index.xml", Astro.site)} />
-<link rel="alternate" type="application/rss+xml" title={SiteMetadata.title} href={new URL("feed.xml", Astro.site)} />
\ No newline at end of file
+<link rel="alternate" type="application/rss+xml" title={siteTitle} href={new URL("feed.xml", Astro.site)} />
\ No newline at end of file
index 91d5ef39c2bf9a6ffcddd9977e18be5437634dd2..9f8a3061a503253c30ecfd227290ca429e178b2f 100644 (file)
@@ -1,24 +1,24 @@
 ---
-import { type CollectionEntry } from 'astro:content';
+import { type InferEntrySchema } from 'astro:content';
 import { formatDate } from '@utils/format.ts';
 import Rating from '@components/ui/rating.astro';
 
 interface Props {
-    entry: CollectionEntry<'articles'> | CollectionEntry<'links'> | CollectionEntry<'reviews'>
+    entryData: InferEntrySchema<'articles'> | InferEntrySchema<'roundups'> | InferEntrySchema<'reviews'>
 }
 
-const { entry } = Astro.props;
-const date = formatDate(entry.data.date);
+const { entryData } = Astro.props;
+const date = formatDate(entryData.date);
 ---
 <details>
     <summary>Metadata</summary>
     <ul>
-        {entry.data.description && <li>Description: {entry.data.description}</li>}
-        {entry.data.rating && <li>Rating: <Rating rating={entry.data.rating} /></li>}
+        {entryData.description && <li>Description: {entryData.description}</li>}
+        {entryData.rating && <li>Rating: <Rating rating={entryData.rating} /></li>}
         <li>Published: <time datetime="">{date}</time></li>
-        <li>Last Modified: <time datetime="">{entry.data.modified ? formatDate(entry.data.modified) : date}</time></li>
-        <li>Tags: {entry.data.tags.join(', ')}</li>
-        {entry.data.posse && <li>POSSE: {Object.entries(entry.data.posse).map((site) => (
+        <li>Last Modified: <time datetime="">{entryData.modified ? formatDate(entryData.modified) : date}</time></li>
+        {entryData.tags && <li>Tags: {entryData.tags.join(', ')}</li>}
+        {entryData.posse && <li>POSSE: {Object.entries(entryData.posse).map((site) => (
             <Fragment>
                 <a href={site[1]}>{site[0]}</a>&nbsp;
             </Fragment>
index d095d1895e11b75e255c79c3862175cba130c4c1..a63792e8a1c14945f156c5e6c78da9d9d23ac828 100644 (file)
@@ -1,9 +1,9 @@
 ---
-import SiteMetadata from '@data/metadata.json';
+import { menuItems } from '@utils/globals.ts';
 ---
 <nav>
     <menu>
-        {SiteMetadata.navMenu.map((menuItem) => {
+        {menuItems.map((menuItem) => {
             return (
                 <li><a href={menuItem.url}>{menuItem.title}</a></li>
             )
index df6e4c8f5ea0b981ca49313400aa8a3456aa50d9..49764b390bd549cf49815523114d9c492adf7bb0 100644 (file)
@@ -1,6 +1,6 @@
 import { BarChart, Bar, XAxis, YAxis, CartesianGrid, ResponsiveContainer, Tooltip } from 'recharts';
 
-export default function Chart({ chartData }) {
+export default function Chart({ chartData }: { chartData: { name: string, count: number }[] }) {
     return (
         <ResponsiveContainer width="100%" height={150}>
             <BarChart data={chartData}>
index e9bd9b55acb474569348f8394e3981cdfab1bc6f..4d06976304be5bfefe3fa71cae8714f1eb694315 100644 (file)
@@ -4,7 +4,7 @@ import Chart from './chart.tsx';
 
 const reviews = await getCollection('reviews');
 
-const ratingCounts = {
+const ratingCounts: { [rating: number]: number } = {
     1: 0,
     2: 0,
     3: 0,
@@ -16,8 +16,8 @@ reviews.forEach(review => {
     ratingCounts[rating]++;
 });
 const chartData = Object.keys(ratingCounts).map(rating => ({
-    name: `${rating}`,
-    count: ratingCounts[rating]
+    name: rating,
+    count: ratingCounts[parseInt(rating)]
 }));
 ---
 <Chart chartData={chartData} client:load />
\ No newline at end of file
index 96adba65d4e45b664f8976955317104222fe1722..ced51c0ce77cdf5af134ddecba93f9bd994946c5 100644 (file)
@@ -13,8 +13,8 @@ const articles = defineCollection({
     })
 });
 
-const links = defineCollection({
-    loader: glob({ pattern: '**/*.{md,mdx}', base: 'content/links' }),
+const roundups = defineCollection({
+    loader: glob({ pattern: '**/*.{md,mdx}', base: 'content/build-weekly-roundup' }),
     schema: z.object({
         title: z.string(),
         href: z.string().url(),
@@ -26,9 +26,17 @@ const links = defineCollection({
     })
 });
 
+const ReviewType = z.enum([
+    "game",
+    "movie",
+    "music",
+    "show"
+])
+
 const reviews = defineCollection({
     loader: glob({ pattern: '**/*.{md,mdx}', base: 'content/reviews' }),
     schema: z.object({
+        type: ReviewType,
         title: z.string(),
         description: z.string().optional(),
         rating: z.number().gt(0).lte(5).step(1),
@@ -39,4 +47,4 @@ const reviews = defineCollection({
     })
 });
 
-export const collections = { articles, links, reviews };
\ No newline at end of file
+export const collections = { articles, roundups, reviews };
\ No newline at end of file
index 24301fbcb12c1aeed97169fd5bccfe3ca4f790b6..bf033045d6657fbe97dc1097d9854a1453107c59 100644 (file)
@@ -27,6 +27,6 @@ const { Content } = await render(article);
      tags={article.data.tags}
 >
     <h2>{article.data.title}</h2>
-    <Metadata entry={article} />
+    <Metadata entryData={article.data} />
     <Content />
 </Article>
\ No newline at end of file
index 7fdfc3346e3f501be22c666ba339701ce7726d66..8165446fc295a60f9ba3735a8eb2af95e75bdb43 100644 (file)
@@ -2,7 +2,7 @@ import type { APIRoute } from 'astro';
 import { getCollection } from 'astro:content';
 import { formatDate } from '@utils/format.ts';
 import { ImageResponse } from '@vercel/og';
-import SiteMetadata from '@data/metadata.json';
+import { siteAuthor } from '@utils/globals.ts';
 
 export async function getStaticPaths() {
     const articles = await getCollection('articles');
@@ -86,13 +86,15 @@ export const GET: APIRoute = async ({ props }) => {
                                     },
                                 },
                             },
-                            SiteMetadata.author.name,
+                            siteAuthor.name,
                         ],
                     },
                 },
             ],
         },
+        key: null
     }
+
     return new ImageResponse(element, {
         width: 1200,
         height: 630,
index 78b1fdd35672dc59033452a45471ec8991075be6..15f595f2aa12a7dcf40433b28f083dcdfa645f53 100644 (file)
@@ -4,7 +4,7 @@ import { formatDate } from '@utils/format.ts';
 import Base from '@layouts/base.astro';
 
 const articles = await getCollection('articles');
-const sortedArticles = articles.sort((a, b) => b.data.date - a.data.date);
+const sortedArticles = articles.sort((a, b) => b.data.date.getTime() - a.data.date.getTime());
 ---
 
 <Base title="Articles" description="Description">
diff --git a/src/pages/build-weekly-roundup/[id]/index.astro b/src/pages/build-weekly-roundup/[id]/index.astro
new file mode 100644 (file)
index 0000000..f354468
--- /dev/null
@@ -0,0 +1,31 @@
+---
+import { type CollectionEntry, getCollection, render } from 'astro:content';
+import Article from '@layouts/article.astro';
+import Metadata from '@components/metadata.astro';
+
+interface Props {
+    roundup: CollectionEntry<'roundups'>
+}
+
+export async function getStaticPaths() {
+    const roundups = await getCollection('roundups');
+    return roundups.map(roundup => ({
+        params: { id: roundup.id },
+        props: { roundup },
+    }));
+}
+
+const { roundup } = Astro.props;
+const { Content } = await render(roundup);
+---
+<Article
+     title={roundup.data.title}
+     description={roundup.data.description}
+     publishedTime={roundup.data.date.toISOString()}
+     modifiedTime={roundup.data.modified ? roundup.data.modified.toISOString() : roundup.data.date.toISOString()}
+     tags={roundup.data.tags}
+>
+    <a href={roundup.data.href}><h2>{roundup.data.title}</h2></a>
+    <Metadata entryData={roundup.data} />
+    <Content />
+</Article>
\ No newline at end of file
similarity index 87%
rename from src/pages/links/[date]-[id]/opengraph.png.ts
rename to src/pages/build-weekly-roundup/[id]/opengraph.png.ts
index 7da951611a0cc1d363136f63a8a85a110d4e072c..c376dd4367a2532fc9a8ea12f31c4d27071d17a6 100644 (file)
@@ -1,14 +1,13 @@
 import type { APIRoute } from 'astro';
 import { getCollection } from 'astro:content';
-import { formatDate } from '@utils/format.ts';
 import { ImageResponse } from '@vercel/og';
-import SiteMetadata from '@data/metadata.json';
+import { siteAuthor } from '@utils/globals.ts';
 
 export async function getStaticPaths() {
-    const links = await getCollection('links');
-    return links.map(article => ({
-        params: { date: formatDate(article.data.date), id: article.id },
-        props: { article },
+    const roundups = await getCollection('roundups');
+    return roundups.map(roundup => ({
+        params: { id: roundup.id },
+        props: { roundup },
     }));
 };
 
@@ -46,7 +45,7 @@ export const GET: APIRoute = async ({ props }) => {
                             fontWeight: 600,
                             marginBottom: 20,
                         },
-                        children: props.article.data.title,
+                        children: props.roundup.data.title,
                     },
                 },
                 {
@@ -56,7 +55,7 @@ export const GET: APIRoute = async ({ props }) => {
                             fontSize: 32,
                             marginBottom: 40,
                         },
-                        children: props.article.data.description,
+                        children: props.roundup.data.description,
                     },
                 },
                 {
@@ -86,13 +85,15 @@ export const GET: APIRoute = async ({ props }) => {
                                     },
                                 },
                             },
-                            SiteMetadata.author.name,
+                            siteAuthor.name,
                         ],
                     },
                 },
             ],
         },
+        key: null
     }
+
     return new ImageResponse(element, {
         width: 1200,
         height: 630,
diff --git a/src/pages/build-weekly-roundup/index.astro b/src/pages/build-weekly-roundup/index.astro
new file mode 100644 (file)
index 0000000..abbbfc2
--- /dev/null
@@ -0,0 +1,23 @@
+---
+import { getCollection } from 'astro:content';
+import { formatDate } from '@utils/format.ts';
+import Base from '@layouts/base.astro';
+
+const roundups = await getCollection('roundups');
+const sortedRoundups = roundups.sort((a, b) => b.data.date.getTime() - a.data.date.getTime());
+---
+
+<Base title="Build Weekly Roundup" description="Description">
+    <h2>Build Weekly Roundup</h2>
+    <dl>
+        {sortedRoundups.map((roundup) => {
+            const date = formatDate(roundup.data.date);
+            return (
+                <dt><a href={`/build-weekly-roundup/${roundup.id}/`}>{roundup.data.title}</a></dt>
+                <dd>
+                    {roundup.data.description}
+                </dd>
+            )
+        })}
+    </dl>
+</Base>
\ No newline at end of file
index 2c82c1a6fa2a685d5618f011eede0c18d75f700c..75e2f770a67a671b7600d4af0f28e218bf9c8499 100644 (file)
@@ -1,7 +1,7 @@
 import rss from '@astrojs/rss';
 import { getCollection } from 'astro:content';
 import { formatDate } from '@utils/format.ts';
-import SiteMetadata from '@data/metadata.json';
+import { siteSubtitle, siteTitle } from '@utils/globals.ts';
 
 export async function GET(context: any) {
   const articles = await getCollection('articles');
@@ -11,25 +11,28 @@ export async function GET(context: any) {
     description: article.data.description,
     link: `/articles/${formatDate(article.data.date)}-${article.id}/`
   }));
-  const links = await getCollection('links');
-  const linkItems = links.map((link) => ({
-    title: link.data.title,
-    pubDate: link.data.date,
-    description: link.data.description,
-    link: `/links/${formatDate(link.data.date)}-${link.id}/`
+
+  const roundups = await getCollection('roundups');
+  const roundupItems = roundups.map((roundup) => ({
+    title: roundup.data.title,
+    pubDate: roundup.data.date,
+    description: roundup.data.description,
+    link: `/build-weekly-roundup/${roundup.id}/`
   }));
+
   const reviews = await getCollection('reviews');
   const reviewItems = reviews.map((review) => ({
     title: review.data.title,
     pubDate: review.data.date,
     description: review.data.description,
-    link: `/reviews/${formatDate(review.data.date)}-${review.id}/`
+    link: `/reviews/${review.data.type}/${review.id}/`
   }));
-  const feedItems = [ ...articleItems, ...linkItems, ...reviewItems ];
-  const sortedFeedItems = feedItems.sort((a, b) => b.pubDate - a.pubDate);
+
+  const feedItems = [ ...articleItems, ...roundupItems, ...reviewItems ];
+  const sortedFeedItems = feedItems.sort((a, b) => b.pubDate.getTime() - a.pubDate.getTime());
   return rss({
-    title: SiteMetadata.title,
-    description: SiteMetadata.subtitle,
+    title: siteTitle,
+    description: siteSubtitle,
     site: context.site,
     items: sortedFeedItems
   });
index 02d551f9fbbf283eed3d336a7c5be0120f3ffc18..125de02c370d15e32ee439babc92d2f7e5aa11b4 100644 (file)
@@ -1,7 +1,29 @@
 ---
-import SiteMetadata from '@data/metadata.json';
 import Base from '@layouts/base.astro';
 import Callout from '@components/ui/callout.astro';
+
+const contributions = [
+       {
+               "title": "Git",
+               "url": "https://git.otsuka.systems"
+       },
+       {
+               "title": "Arch User Repository",
+               "url": "https://aur.archlinux.org/packages?O=0&SeB=M&K=cotsuka&outdated=&SB=p&SO=d&PP=50&submit=Go"
+       },
+       {
+               "title": "ArchWiki",
+               "url": "https://wiki.archlinux.org/title/Special:Contributions/Cotsuka"
+       },
+       {
+               "title": "GitHub",
+               "url": "https://github.com/search?q=author%3Acotsuka&type=pullrequests"
+       },
+       {
+               "title": "Wikipedia",
+               "url": "https://en.wikipedia.org/wiki/Special:Contributions/Cotsuka"
+       }
+];
 ---
 
 <Base title="Home" description="Description">
@@ -15,7 +37,7 @@ import Callout from '@components/ui/callout.astro';
     <section>
                <h2>Contributions</h2>
                <ul>
-                       {SiteMetadata.contributions.map((contribution) => {
+                       {contributions.map((contribution) => {
                                return (
                                        <li><a href={contribution.url}>{contribution.title}</a></li>
                                )
diff --git a/src/pages/links/[date]-[id]/index.astro b/src/pages/links/[date]-[id]/index.astro
deleted file mode 100644 (file)
index 1707981..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
----
-import { type CollectionEntry, getCollection, render } from 'astro:content';
-import { formatDate } from '@utils/format.ts';
-import Article from '@layouts/article.astro';
-import Metadata from '@components/metadata.astro';
-
-interface Props {
-    link: CollectionEntry<'links'>
-}
-
-export async function getStaticPaths() {
-    const links = await getCollection('links');
-    return links.map(link => ({
-        params: { date: formatDate(link.data.date), id: link.id },
-        props: { link },
-    }));
-}
-
-const { link } = Astro.props;
-const date = formatDate(link.data.date);
-const { Content } = await render(link);
----
-<Article
-     title={link.data.title}
-     description={link.data.description}
-     publishedTime={link.data.date.toISOString()}
-     modifiedTime={link.data.modified ? link.data.modified.toISOString() : link.data.date.toISOString()}
-     tags={link.data.tags}
->
-    <a href={link.data.href}><h2>{link.data.title}</h2></a>
-    <Metadata entry={link} />
-    <Content />
-</Article>
\ No newline at end of file
diff --git a/src/pages/links/index.astro b/src/pages/links/index.astro
deleted file mode 100644 (file)
index befffac..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
----
-import { getCollection } from 'astro:content';
-import { formatDate } from '@utils/format.ts';
-import Base from '@layouts/base.astro';
-
-const links = await getCollection('links');
-const sortedLinks = links.sort((a, b) => b.data.date - a.data.date);
----
-
-<Base title="Links" description="Description">
-    <h2>Links</h2>
-    <dl>
-        {sortedLinks.map((link) => {
-            const date = formatDate(link.data.date);
-            return (
-                <dt><a href={`/links/${date}-${link.id}/`}>{link.data.title}</a></dt>
-                <dd>
-                    {link.data.description}
-                </dd>
-            )
-        })}
-    </dl>
-</Base>
\ No newline at end of file
similarity index 76%
rename from src/pages/reviews/[date]-[id]/index.astro
rename to src/pages/reviews/[type]/[id]/index.astro
index 4afb671a7ce0770ec1e41721e16f97495a84f537..137e310432b568b98154319b0f69e7380dc7aed0 100644 (file)
@@ -1,6 +1,5 @@
 ---
 import { type CollectionEntry, getCollection, render } from 'astro:content';
-import { formatDate } from '@utils/format.ts';
 import Article from '@layouts/article.astro';
 import Metadata from '@components/metadata.astro';
 
@@ -11,23 +10,22 @@ interface Props {
 export async function getStaticPaths() {
     const reviews = await getCollection('reviews');
     return reviews.map(review => ({
-        params: { date: formatDate(review.data.date), id: review.id },
+        params: { type: review.data.type, id: review.id },
         props: { review },
     }));
 }
 
 const { review } = Astro.props;
-const date = formatDate(review.data.date);
 const { Content } = await render(review);
 ---
 <Article
      title={review.data.title}
-     description={review.data.description}
+     description={review.data.description ? review.data.description : ""}
      publishedTime={review.data.date.toISOString()}
      modifiedTime={review.data.modified ? review.data.modified.toISOString() : review.data.date.toISOString()}
      tags={review.data.tags}
 >
     <h2>{review.data.title}</h2>
-    <Metadata entry={review} />
+    <Metadata entryData={review.data} />
     <Content />
 </Article>
\ No newline at end of file
similarity index 88%
rename from src/pages/reviews/[date]-[id]/opengraph.png.ts
rename to src/pages/reviews/[type]/[id]/opengraph.png.ts
index 59bb8a8bb700ec322f0022de1d915214c4c9a255..15713eaf76f6cadc330205973e5b29eea08639b3 100644 (file)
@@ -1,14 +1,13 @@
 import type { APIRoute } from 'astro';
 import { getCollection } from 'astro:content';
-import { formatDate } from '@utils/format.ts';
 import { ImageResponse } from '@vercel/og';
-import SiteMetadata from '@data/metadata.json';
+import { siteAuthor } from '@utils/globals.ts';
 
 export async function getStaticPaths() {
     const reviews = await getCollection('reviews');
-    return reviews.map(article => ({
-        params: { date: formatDate(article.data.date), id: article.id },
-        props: { article },
+    return reviews.map(review => ({
+        params: { type: review.data.type, id: review.id },
+        props: { review },
     }));
 };
 
@@ -46,7 +45,7 @@ export const GET: APIRoute = async ({ props }) => {
                             fontWeight: 600,
                             marginBottom: 20,
                         },
-                        children: props.article.data.title,
+                        children: props.review.data.title,
                     },
                 },
                 {
@@ -56,7 +55,7 @@ export const GET: APIRoute = async ({ props }) => {
                             fontSize: 32,
                             marginBottom: 40,
                         },
-                        children: props.article.data.description,
+                        children: props.review.data.description,
                     },
                 },
                 {
@@ -86,13 +85,15 @@ export const GET: APIRoute = async ({ props }) => {
                                     },
                                 },
                             },
-                            SiteMetadata.author.name,
+                            siteAuthor.name,
                         ],
                     },
                 },
             ],
         },
+        key: null
     }
+
     return new ImageResponse(element, {
         width: 1200,
         height: 630,
index 53bb831d10fb74d9ad98f67545fe5db17b2aebcc..af2ca589cc3db365f71df23fe19ac7879732723d 100644 (file)
@@ -6,7 +6,7 @@ import RatingDistribution from '@components/ratingdistribution/component.astro';
 import Rating from '@components/ui/rating.astro';
 
 const reviews = await getCollection('reviews');
-const sortedReviews = reviews.sort((a, b) => b.data.date - a.data.date);
+const sortedReviews = reviews.sort((a, b) => b.data.date.getTime() - a.data.date.getTime());
 ---
 
 <Base title="Reviews" description="Description">
@@ -20,7 +20,7 @@ const sortedReviews = reviews.sort((a, b) => b.data.date - a.data.date);
             {sortedReviews.map((review) => {
                 const date = formatDate(review.data.date);
                 return (
-                    <dt><a href={`/reviews/${date}-${review.id}/`}>{review.data.title}</a></dt>
+                    <dt><a href={`/reviews/${review.data.type}/${review.id}/`}>{review.data.title}</a></dt>
                     <dd>
                         <Rating rating={review.data.rating} />
                     </dd>
diff --git a/src/utils/globals.ts b/src/utils/globals.ts
new file mode 100644 (file)
index 0000000..89ac40e
--- /dev/null
@@ -0,0 +1,35 @@
+export const siteTitle = "Cameron Otsuka";
+export const siteSubtitle = "The collection of Cameron's thoughts."
+export const siteAuthor = {
+  "name": "Cameron Otsuka",
+  "email": "cameron@otsuka.haus"
+}
+
+export const menuItems: {title: string, url: string}[] = [
+    { "title": "Podcast", "url": "/build-weekly-roundup" },
+    { "title": "Articles", "url": "/articles" },
+    { "title": "Reviews", "url": "/reviews" }
+];
+
+export const socials: { [platform: string]: { title: string, url: string, username: string } } = {
+  "x": {
+    "title": "𝕏",
+    "url": "https://x.com/CameronOtsuka",
+    "username": "@CameronOtsuka"
+  },
+  "linkedin": {
+    "title": "LinkedIn",
+    "url": "https://www.linkedin.com/in/cotsuka",
+    "username": "cotsuka"
+  },
+  "activitypub": {
+    "title": "ActivityPub",
+    "url": "https://social.otsuka.systems/@cameron",
+    "username": "@cameron@otsuka.systems"
+  },
+  "nostr": {
+    "title": "Nostr",
+    "url": "https://primal.net/profile/npub1hzssq7wewjztvglpdvku92htx3sv2x5r9ycvqhvl9xrtt5fn629s3np693",
+    "username": "cameron@otsuka.systems"
+  }
+};
\ No newline at end of file
index c4aa0ea06d5f81c3b2247be9060cf07b3bf13375..2f13868f4317fbfc1be9ca69bd0bb7baf6aedb8c 100644 (file)
@@ -8,30 +8,28 @@
     "dist"
   ],
   "compilerOptions": {
-    "baseUrl": ".",
+    "baseUrl": "src/",
     "paths": {
       "@assets/*": [
-        "src/assets/*"
+        "assets/*"
       ],
       "@components/*": [
-        "src/components/*"
-      ],
-      "@data/*": [
-        "data/*"
+        "components/*"
       ],
       "@layouts/*": [
-        "src/layouts/*"
+        "layouts/*"
       ],
       "@styles/*": [
-        "src/styles/*"
+        "styles/*"
       ],
       "@utils/*": [
-        "src/utils/*"
+        "utils/*"
       ]
     },
     "allowSyntheticDefaultImports": true,
     "allowImportingTsExtensions": true,
     "jsx": "react-jsx",
-    "jsxImportSource": "react"
+    "jsxImportSource": "react",
+    "resolveJsonModule": true
   }
 }
\ No newline at end of file