From fc38a1aafe04245cb477b97299ee7a899f42ae3e Mon Sep 17 00:00:00 2001 From: Dave Date: Wed, 23 Sep 2026 13:26:37 +0200 Subject: [PATCH] Added meta to layouts --- eslint.config.mjs | 6 ++- package.json | 5 +- pnpm-lock.yaml | 67 +++++++++++++++++-------- src/layouts/BaseLayout.astro | 18 ++++++- src/layouts/general/ArticleLayout.astro | 4 +- src/layouts/general/PageLayout.astro | 4 +- src/lib/content/dates.ts | 11 ++++ src/lib/site/meta.ts | 18 +++++++ 8 files changed, 106 insertions(+), 27 deletions(-) create mode 100644 src/lib/site/meta.ts diff --git a/eslint.config.mjs b/eslint.config.mjs index 8acfa76..ee7304a 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -3,6 +3,7 @@ import prettier from 'eslint-config-prettier/flat' import astro from 'eslint-plugin-astro' import reactHooks from 'eslint-plugin-react-hooks' import unusedImports from 'eslint-plugin-unused-imports' +import globals from 'globals' import tseslint from 'typescript-eslint' export default [ @@ -11,7 +12,10 @@ export default [ js.configs.recommended, ...tseslint.configs.recommended, ...astro.configs.recommended, - + { + name: 'dave-dmg/node', + languageOptions: { globals: globals.node }, + }, { name: 'dave-dmg/unused', files: ['**/*.{js,mjs,cjs,ts,tsx,astro}'], diff --git a/package.json b/package.json index f357484..c14e55a 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "@csstools/postcss-global-data": "^4.0.0", "@eslint/js": "^10.0.1", "@ianvs/prettier-plugin-sort-imports": "^4.7.1", + "@types/node": "^22.20.4", "@types/react": "^19.2.18", "@types/react-dom": "^19.2.4", "eslint": "^10.11.0", @@ -35,6 +36,7 @@ "eslint-plugin-astro": "^3.2.1", "eslint-plugin-react-hooks": "^7.1.1", "eslint-plugin-unused-imports": "^4.4.1", + "globals": "^17.12.0", "postcss": "^8.5.28", "postcss-custom-media": "^12.0.1", "postcss-mixins": "^12.1.2", @@ -46,7 +48,8 @@ "stylelint-config-html": "^2.0.0", "stylelint-config-standard": "^40.0.0", "typescript": "~6.0.3", - "typescript-eslint": "^8.70.0" + "typescript-eslint": "^8.70.0", + "vite": "^8.3.0" }, "packageManager": "pnpm@10.15.0", "engines": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 32c014a..ad7dc1b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,16 +13,16 @@ importers: dependencies: '@astrojs/node': specifier: ^11.0.0 - version: 11.1.6(astro@7.3.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(idb-keyval@6.3.0)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1)) + version: 11.1.6(astro@7.3.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@22.20.4)(idb-keyval@6.3.0)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1)) '@astrojs/react': specifier: ^6.0.0 - version: 6.0.6(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(esbuild@0.28.2)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1) + version: 6.0.6(@types/node@22.20.4)(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(esbuild@0.28.2)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1) '@keystar/ui': specifier: ^0.10.0 version: 0.10.0(react-aria@3.50.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react-dom@19.3.0(react@19.3.0))(react-stately@3.48.0(react@19.3.0))(react@19.3.0) '@keystatic/astro': specifier: ^6.0.0 - version: 6.0.0(@keystatic/core@0.6.9(@keystar/ui@0.10.0(react-aria@3.50.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react-dom@19.3.0(react@19.3.0))(react-stately@3.48.0(react@19.3.0))(react@19.3.0))(react-aria@3.50.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react-dom@19.3.0(react@19.3.0))(react-stately@3.48.0(react@19.3.0))(react@19.3.0))(astro@7.3.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(idb-keyval@6.3.0)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1))(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + version: 6.0.0(@keystatic/core@0.6.9(@keystar/ui@0.10.0(react-aria@3.50.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react-dom@19.3.0(react@19.3.0))(react-stately@3.48.0(react@19.3.0))(react@19.3.0))(react-aria@3.50.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react-dom@19.3.0(react@19.3.0))(react-stately@3.48.0(react@19.3.0))(react@19.3.0))(astro@7.3.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@22.20.4)(idb-keyval@6.3.0)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1))(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@keystatic/core': specifier: ^0.6.7 version: 0.6.9(@keystar/ui@0.10.0(react-aria@3.50.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react-dom@19.3.0(react@19.3.0))(react-stately@3.48.0(react@19.3.0))(react@19.3.0))(react-aria@3.50.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react-dom@19.3.0(react@19.3.0))(react-stately@3.48.0(react@19.3.0))(react@19.3.0) @@ -31,7 +31,7 @@ importers: version: 0.4.0(@types/react@19.3.0)(react@19.3.0) astro: specifier: ^7.0.4 - version: 7.3.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(idb-keyval@6.3.0)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1) + version: 7.3.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@22.20.4)(idb-keyval@6.3.0)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1) react: specifier: ^19.2.8 version: 19.3.0 @@ -40,7 +40,7 @@ importers: version: 19.3.0(react@19.3.0) sharp: specifier: ^0.35.4 - version: 0.35.4 + version: 0.35.4(@types/node@22.20.4) devDependencies: '@astrojs/check': specifier: ^0.9.10 @@ -54,6 +54,9 @@ importers: '@ianvs/prettier-plugin-sort-imports': specifier: ^4.7.1 version: 4.7.1(prettier@3.9.8) + '@types/node': + specifier: ^22.20.4 + version: 22.20.4 '@types/react': specifier: ^19.2.18 version: 19.3.0 @@ -75,6 +78,9 @@ importers: eslint-plugin-unused-imports: specifier: ^4.4.1 version: 4.4.1(@typescript-eslint/eslint-plugin@8.70.0(@typescript-eslint/parser@8.70.0(eslint@10.11.0)(typescript@6.0.3))(eslint@10.11.0)(typescript@6.0.3))(eslint@10.11.0) + globals: + specifier: ^17.12.0 + version: 17.12.0 postcss: specifier: ^8.5.28 version: 8.5.28 @@ -111,6 +117,9 @@ importers: typescript-eslint: specifier: ^8.70.0 version: 8.70.0(eslint@10.11.0)(typescript@6.0.3) + vite: + specifier: ^8.3.0 + version: 8.3.0(@types/node@22.20.4)(esbuild@0.28.2)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1) packages: @@ -1247,6 +1256,9 @@ packages: '@types/nlcst@2.0.3': resolution: {integrity: sha512-vSYNSDe6Ix3q+6Z7ri9lyWqgGhJTmzRjZRqyq15N0Z/1/UnVsno9G/N40NBijoYx2seFDIl0+B2mgAb9mezUCA==} + '@types/node@22.20.4': + resolution: {integrity: sha512-zJRE40jpHtKqE/C4fgHrAKQLJuSpzEnP9ff9Y7YtoR3Wd2pwqzlekDeEuUQXjRd+QCYnVnNwuJYmhdk9XV8gvA==} + '@types/react-dom@19.3.0': resolution: {integrity: sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==} peerDependencies: @@ -3118,6 +3130,9 @@ packages: uncrypto@0.1.3: resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici@8.10.2: resolution: {integrity: sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ==} engines: {node: '>=22.19.0'} @@ -3629,10 +3644,10 @@ snapshots: github-slugger: 2.0.0 satteri: 0.10.5 - '@astrojs/node@11.1.6(astro@7.3.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(idb-keyval@6.3.0)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1))': + '@astrojs/node@11.1.6(astro@7.3.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@22.20.4)(idb-keyval@6.3.0)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1))': dependencies: '@astrojs/internal-helpers': 0.11.0 - astro: 7.3.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(idb-keyval@6.3.0)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1) + astro: 7.3.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@22.20.4)(idb-keyval@6.3.0)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1) send: 1.2.1 server-destroy: 1.0.1 transitivePeerDependencies: @@ -3642,17 +3657,17 @@ snapshots: dependencies: prismjs: 1.30.0 - '@astrojs/react@6.0.6(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(esbuild@0.28.2)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1)': + '@astrojs/react@6.0.6(@types/node@22.20.4)(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(esbuild@0.28.2)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1)': dependencies: '@astrojs/internal-helpers': 0.11.0 '@types/react': 19.3.0 '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@vitejs/plugin-react': 5.2.0(vite@8.3.0(esbuild@0.28.2)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1)) + '@vitejs/plugin-react': 5.2.0(vite@8.3.0(@types/node@22.20.4)(esbuild@0.28.2)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1)) devalue: 5.9.4 react: 19.3.0 react-dom: 19.3.0(react@19.3.0) ultrahtml: 1.7.0 - vite: 8.3.0(esbuild@0.28.2)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1) + vite: 8.3.0(@types/node@22.20.4)(esbuild@0.28.2)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1) transitivePeerDependencies: - '@types/node' - '@vitejs/devtools' @@ -4300,12 +4315,12 @@ snapshots: react-dom: 19.3.0(react@19.3.0) react-stately: 3.48.0(react@19.3.0) - '@keystatic/astro@6.0.0(@keystatic/core@0.6.9(@keystar/ui@0.10.0(react-aria@3.50.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react-dom@19.3.0(react@19.3.0))(react-stately@3.48.0(react@19.3.0))(react@19.3.0))(react-aria@3.50.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react-dom@19.3.0(react@19.3.0))(react-stately@3.48.0(react@19.3.0))(react@19.3.0))(astro@7.3.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(idb-keyval@6.3.0)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + '@keystatic/astro@6.0.0(@keystatic/core@0.6.9(@keystar/ui@0.10.0(react-aria@3.50.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react-dom@19.3.0(react@19.3.0))(react-stately@3.48.0(react@19.3.0))(react@19.3.0))(react-aria@3.50.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react-dom@19.3.0(react@19.3.0))(react-stately@3.48.0(react@19.3.0))(react@19.3.0))(astro@7.3.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@22.20.4)(idb-keyval@6.3.0)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: '@babel/runtime': 7.29.7 '@keystatic/core': 0.6.9(@keystar/ui@0.10.0(react-aria@3.50.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react-dom@19.3.0(react@19.3.0))(react-stately@3.48.0(react@19.3.0))(react@19.3.0))(react-aria@3.50.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(react-dom@19.3.0(react@19.3.0))(react-stately@3.48.0(react@19.3.0))(react@19.3.0) '@types/react': 19.3.0 - astro: 7.3.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(idb-keyval@6.3.0)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1) + astro: 7.3.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@22.20.4)(idb-keyval@6.3.0)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1) react: 19.3.0 react-dom: 19.3.0(react@19.3.0) @@ -4616,6 +4631,10 @@ snapshots: dependencies: '@types/unist': 3.0.3 + '@types/node@22.20.4': + dependencies: + undici-types: 6.21.0 + '@types/react-dom@19.3.0(@types/react@19.3.0)': dependencies: '@types/react': 19.3.0 @@ -4746,7 +4765,7 @@ snapshots: '@urql/core': 5.2.0(graphql@16.14.2) wonka: 6.3.6 - '@vitejs/plugin-react@5.2.0(vite@8.3.0(esbuild@0.28.2)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1))': + '@vitejs/plugin-react@5.2.0(vite@8.3.0(@types/node@22.20.4)(esbuild@0.28.2)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1))': dependencies: '@babel/core': 7.29.7 '@babel/plugin-transform-react-jsx-self': 7.29.7(@babel/core@7.29.7) @@ -4754,7 +4773,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-rc.3 '@types/babel__core': 7.20.5 react-refresh: 0.18.0 - vite: 8.3.0(esbuild@0.28.2)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1) + vite: 8.3.0(@types/node@22.20.4)(esbuild@0.28.2)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1) transitivePeerDependencies: - supports-color @@ -4881,7 +4900,7 @@ snapshots: - '@emnapi/runtime' - supports-color - astro@7.3.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(idb-keyval@6.3.0)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1): + astro@7.3.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@22.20.4)(idb-keyval@6.3.0)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1): dependencies: '@astrojs/compiler-rs': 0.4.1(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) '@astrojs/internal-helpers': 0.11.0 @@ -4931,13 +4950,13 @@ snapshots: unifont: 0.7.5 unstorage: 1.17.5(idb-keyval@6.3.0) verkit: 0.4.1 - vite: 8.3.0(esbuild@0.28.2)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1) - vitefu: 1.1.3(vite@8.3.0(esbuild@0.28.2)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1)) + vite: 8.3.0(@types/node@22.20.4)(esbuild@0.28.2)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1) + vitefu: 1.1.3(vite@8.3.0(@types/node@22.20.4)(esbuild@0.28.2)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1)) xxhash-wasm: 1.1.0 yargs-parser: 22.0.0 zod: 4.6.5 optionalDependencies: - sharp: 0.35.4 + sharp: 0.35.4(@types/node@22.20.4) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -6546,7 +6565,7 @@ snapshots: setprototypeof@1.2.0: {} - sharp@0.35.4: + sharp@0.35.4(@types/node@22.20.4): dependencies: '@img/colour': 1.1.0 detect-libc: 2.1.2 @@ -6577,6 +6596,7 @@ snapshots: '@img/sharp-win32-arm64': 0.35.4 '@img/sharp-win32-ia32': 0.35.4 '@img/sharp-win32-x64': 0.35.4 + '@types/node': 22.20.4 shebang-command@2.0.0: dependencies: @@ -6854,6 +6874,8 @@ snapshots: uncrypto@0.1.3: {} + undici-types@6.21.0: {} + undici@8.10.2: {} unicorn-magic@0.4.0: {} @@ -6948,7 +6970,7 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite@8.3.0(esbuild@0.28.2)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1): + vite@8.3.0(@types/node@22.20.4)(esbuild@0.28.2)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1): dependencies: lightningcss: 1.33.0 picomatch: 4.0.7 @@ -6956,14 +6978,15 @@ snapshots: rolldown: 1.2.9 tinyglobby: 0.2.17 optionalDependencies: + '@types/node': 22.20.4 esbuild: 0.28.2 fsevents: 2.3.3 sugarss: 5.0.1(postcss@8.5.28) yaml: 2.9.1 - vitefu@1.1.3(vite@8.3.0(esbuild@0.28.2)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1)): + vitefu@1.1.3(vite@8.3.0(@types/node@22.20.4)(esbuild@0.28.2)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1)): optionalDependencies: - vite: 8.3.0(esbuild@0.28.2)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1) + vite: 8.3.0(@types/node@22.20.4)(esbuild@0.28.2)(sugarss@5.0.1(postcss@8.5.28))(yaml@2.9.1) volar-service-css@0.0.71(@volar/language-service@2.4.28): dependencies: diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro index 3536b6d..542975d 100644 --- a/src/layouts/BaseLayout.astro +++ b/src/layouts/BaseLayout.astro @@ -3,12 +3,19 @@ import { Font } from 'astro:assets' import '@/styles/global.css' +import { resolveImage } from '@/lib/images/resolve' + interface Props { title: string description?: string + image?: string + noindex?: boolean } -const { title, description } = Astro.props +const { title, description, image, noindex } = Astro.props +const canonical = new URL(Astro.url.pathname, Astro.site) +const preview = image ? resolveImage(image) : undefined +const previewUrl = preview ? new URL(preview.src, Astro.site) : undefined --- @@ -20,6 +27,15 @@ const { title, description } = Astro.props {title} {description && } + {noindex && } + + + + + + {description && } + {previewUrl && } + diff --git a/src/layouts/general/ArticleLayout.astro b/src/layouts/general/ArticleLayout.astro index 85ccec3..b83223d 100644 --- a/src/layouts/general/ArticleLayout.astro +++ b/src/layouts/general/ArticleLayout.astro @@ -6,6 +6,7 @@ import Node from '@/components/markdoc/Node.astro' import Figure from '@/components/media/Figure.astro' import BaseLayout from '@/layouts/BaseLayout.astro' import type { Rendered } from '@/lib/markdoc/types' +import { metaOf } from '@/lib/site/meta' import type { Article } from '@/lib/site/types' type Props = { @@ -14,9 +15,10 @@ type Props = { } const { article, rendered } = Astro.props +const meta = metaOf(article) --- - + + DISPLAY.format(date) + +export const isoDate = (date: Date): string => date.toISOString().slice(0, 10) diff --git a/src/lib/site/meta.ts b/src/lib/site/meta.ts new file mode 100644 index 0000000..f1b0927 --- /dev/null +++ b/src/lib/site/meta.ts @@ -0,0 +1,18 @@ +import type { Article, Page, Routed } from './types' + +export type Meta = { + title: string + description?: string + image?: string + noindex: boolean +} + +const cover = (node: Routed) => + node.collection === 'articles' ? (node as Article).summary.cover.image : null + +export const metaOf = (node: Article | Page): Meta => ({ + title: node.title, + description: node.summary.excerpt || undefined, + image: cover(node) ?? undefined, + noindex: node.noindex, +})