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
+
{jsonLd && }