diff --git a/.gitignore b/.gitignore index d637705..435e4c0 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ node_modules/ dist/ .astro/ + +# OG image must ship despite the *.png rule +!public/assets/img/logo/traverse_icon_1024x1024.png diff --git a/astro.config.mjs b/astro.config.mjs index 69c1fc0..9e7e6e2 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -1,4 +1,5 @@ import { defineConfig } from 'astro/config'; +import sitemap from '@astrojs/sitemap'; export default defineConfig({ site: 'https://traverse-framework.com', @@ -7,4 +8,16 @@ export default defineConfig({ format: 'file', }, trailingSlash: 'never', + integrations: [ + sitemap({ + serialize(item) { + // build.format 'file' emits .html pages; make sitemap URLs match canonicals + const url = new URL(item.url); + if (url.pathname !== '/' && !url.pathname.endsWith('.html')) { + item.url = `${url.origin}${url.pathname}.html`; + } + return item; + }, + }), + ], }); diff --git a/package-lock.json b/package-lock.json index 44e5c12..2df467a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "traverse-website", "version": "0.1.0", "dependencies": { + "@astrojs/sitemap": "^3.7.3", "astro": "^5.0.0" } }, @@ -64,6 +65,26 @@ "node": "18.20.8 || ^20.3.0 || >=22.0.0" } }, + "node_modules/@astrojs/sitemap": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/@astrojs/sitemap/-/sitemap-3.7.3.tgz", + "integrity": "sha512-f8euLVsyeAmAkSm/1M2Kb8sL8byQmfgbvBNaHFItCheTj/IpiJYSEWVcqDHZ/yEHxiS7+w87mQkzwZaPHmk5GA==", + "license": "MIT", + "dependencies": { + "sitemap": "^9.0.0", + "stream-replace-string": "^2.0.0", + "zod": "^4.3.6" + } + }, + "node_modules/@astrojs/sitemap/node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/@astrojs/telemetry": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.0.tgz", @@ -1599,6 +1620,24 @@ "@types/unist": "*" } }, + "node_modules/@types/node": { + "version": "24.13.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.2.tgz", + "integrity": "sha512-fRa09kZTgu8o71KFcDjUFuc7F+dEbZYZmkI0mg5YBTRs0yMKjYHsq/c0urDKeDb+D5qVgXOdFcuu+DZPKOITwA==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/sax": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/sax/-/sax-1.2.7.tgz", + "integrity": "sha512-rO73L89PJxeYM3s3pPPjiPgVVcymqU490g0YO5n5By0k2Erzj6tay/4lr1CHAAU4JyOWd1rpQ8bCf6cZfHU96A==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/unist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", @@ -1722,6 +1761,12 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -4341,6 +4386,25 @@ "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", "license": "MIT" }, + "node_modules/sitemap": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-9.0.1.tgz", + "integrity": "sha512-S6hzjGJSG3d6if0YoF5kTyeRJvia6FSTBroE5fQ0bu1QNxyJqhhinfUsXi9fH3MgtXODWvwo2BDyQSnhPQ88uQ==", + "license": "MIT", + "dependencies": { + "@types/node": "^24.9.2", + "@types/sax": "^1.2.1", + "arg": "^5.0.0", + "sax": "^1.4.1" + }, + "bin": { + "sitemap": "dist/esm/cli.js" + }, + "engines": { + "node": ">=20.19.5", + "npm": ">=10.8.2" + } + }, "node_modules/smol-toml": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.7.0.tgz", @@ -4372,6 +4436,12 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/stream-replace-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/stream-replace-string/-/stream-replace-string-2.0.0.tgz", + "integrity": "sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==", + "license": "MIT" + }, "node_modules/string-width": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", @@ -4566,6 +4636,12 @@ "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==", "license": "MIT" }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "license": "MIT" + }, "node_modules/unified": { "version": "11.0.5", "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", diff --git a/package.json b/package.json index e76cce5..83519e0 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "astro": "astro" }, "dependencies": { + "@astrojs/sitemap": "^3.7.3", "astro": "^5.0.0" } } diff --git a/public/robots.txt b/public/robots.txt index d6c801c..79542e4 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -1,4 +1,4 @@ User-agent: * Allow: / -Sitemap: https://traverse-framework.com/sitemap.xml +Sitemap: https://traverse-framework.com/sitemap-index.xml diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro index bdaa99e..3938e87 100644 --- a/src/layouts/BaseLayout.astro +++ b/src/layouts/BaseLayout.astro @@ -16,10 +16,31 @@ const { description, canonical = Astro.url.href, jsonLd, - ogImage = '/assets/img/og-default.png', + ogImage = '/assets/img/logo/traverse_icon_1024x1024.png', } = Astro.props; const fullTitle = title.includes('Traverse') ? title : `${title} — Traverse Framework`; +const ogImageAbs = new URL(ogImage, Astro.site).href; + +const siteJsonLd = JSON.stringify({ + '@context': 'https://schema.org', + '@graph': [ + { + '@type': 'Organization', + '@id': 'https://traverse-framework.com/#organization', + name: 'Traverse Framework', + url: 'https://traverse-framework.com/', + logo: 'https://traverse-framework.com/assets/img/logo/traverse_icon_512x512.svg', + }, + { + '@type': 'WebSite', + '@id': 'https://traverse-framework.com/#website', + name: 'Traverse Framework', + url: 'https://traverse-framework.com/', + publisher: { '@id': 'https://traverse-framework.com/#organization' }, + }, + ], +}); --- @@ -35,8 +56,12 @@ const fullTitle = title.includes('Traverse') ? title : `${title} — Traverse Fr - + + + + + @@ -48,6 +73,7 @@ const fullTitle = title.includes('Traverse') ? title : `${title} — Traverse Fr +