sum more SEO changes

This commit is contained in:
2026-06-29 17:01:53 +01:00
parent acd84b0c75
commit deeb46ce8e
+55 -2
View File
@@ -2365,6 +2365,10 @@ function escapeHtml(value) {
.replace(/'/g, ''') .replace(/'/g, ''')
} }
function stripSiteTitle(title) {
return String(title || '').replace(/\s+\|\s+Toothless' TSS Bot$/, '')
}
function decodeRouteSegment(value) { function decodeRouteSegment(value) {
try { try {
return decodeURIComponent(value || '').replace(/\+/g, ' ').trim() return decodeURIComponent(value || '').replace(/\+/g, ' ').trim()
@@ -2617,6 +2621,54 @@ function routeSeo(pathname) {
return byPath[cleanPath] || notFoundSeo return byPath[cleanPath] || notFoundSeo
} }
function routeFallbackSections(seo) {
const sections = [
{ href: '/teams', label: 'TSS team leaderboard' },
{ href: '/players', label: 'TSS player leaderboard' },
{ href: '/battle-logs', label: 'Battle logs' },
{ href: '/tournaments', label: 'Tournaments' },
{ href: '/blog', label: 'Blog' },
]
if (seo.status === 404) {
return [
'<p>Use the links below to browse the live War Thunder Tournament Service leaderboards, battle logs, tournament brackets, and updates.</p>',
`<nav aria-label="Main sections"><ul>${sections.map((section) => `<li><a href="${section.href}">${escapeHtml(section.label)}</a></li>`).join('')}</ul></nav>`,
].join('\n')
}
if (seo.type === 'BlogPosting') {
const published = seo.publishedAt ? `<p>Published ${escapeHtml(seo.publishedAt)} by ${escapeHtml(seo.author || "Toothless' TSS Bot")}.</p>` : ''
return [
published,
'<p>Read more War Thunder TSS Bot news, feature updates, tournament tracking notes, and community announcements.</p>',
'<p><a href="/blog">Browse all blog posts</a></p>',
].filter(Boolean).join('\n')
}
if (seo.path === '/') {
return [
'<p>Toothless TSS Bot tracks War Thunder Tournament Service activity across teams, players, battle logs, tournaments, and squadron profiles.</p>',
`<nav aria-label="Main sections"><ul>${sections.map((section) => `<li><a href="${section.href}">${escapeHtml(section.label)}</a></li>`).join('')}</ul></nav>`,
].join('\n')
}
return [
'<p>This page is part of Toothless TSS Bot, a War Thunder Tournament Service tracker for leaderboards, squadron profiles, battle logs, player stats, and tournament brackets.</p>',
`<nav aria-label="Related sections"><ul>${sections.filter((section) => section.href !== seo.path).map((section) => `<li><a href="${section.href}">${escapeHtml(section.label)}</a></li>`).join('')}</ul></nav>`,
].join('\n')
}
function routeFallbackHtml(seo) {
return [
'<main id="seo-fallback">',
`<h1>${escapeHtml(stripSiteTitle(seo.title))}</h1>`,
`<p>${escapeHtml(seo.description)}</p>`,
routeFallbackSections(seo),
'</main>',
].join('\n')
}
function routeStructuredData(origin, seo, canonicalUrl) { function routeStructuredData(origin, seo, canonicalUrl) {
const siteId = `${origin}/#website` const siteId = `${origin}/#website`
const pageId = `${canonicalUrl}#webpage` const pageId = `${canonicalUrl}#webpage`
@@ -2661,7 +2713,7 @@ function routeStructuredData(origin, seo, canonicalUrl) {
...(seo.path === '/' ? [] : [{ ...(seo.path === '/' ? [] : [{
'@type': 'ListItem', '@type': 'ListItem',
position: 2, position: 2,
name: seo.title.replace(/\s+\|\s+Toothless' TSS Bot$/, ''), name: stripSiteTitle(seo.title),
item: canonicalUrl, item: canonicalUrl,
}]), }]),
], ],
@@ -2672,7 +2724,7 @@ function routeStructuredData(origin, seo, canonicalUrl) {
items.push({ items.push({
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@type': 'BlogPosting', '@type': 'BlogPosting',
headline: seo.title.replace(/\s+\|\s+Toothless' TSS Bot$/, ''), headline: stripSiteTitle(seo.title),
description: seo.description, description: seo.description,
url: canonicalUrl, url: canonicalUrl,
image: imageUrl, image: imageUrl,
@@ -2725,6 +2777,7 @@ function htmlWithSeo(req, data) {
.replaceAll('__SEO_MODIFIED_TIME__', escapeHtml(seo.publishedAt || '')) .replaceAll('__SEO_MODIFIED_TIME__', escapeHtml(seo.publishedAt || ''))
.replaceAll('__SEO_JSON_LD__', routeStructuredData(origin, seo, canonicalUrl).replace(/</g, '\\u003c')) .replaceAll('__SEO_JSON_LD__', routeStructuredData(origin, seo, canonicalUrl).replace(/</g, '\\u003c'))
.replaceAll('__TURNSTILE_SESSION__', isTurnstileSessionVerified(req) ? 'verified' : 'required') .replaceAll('__TURNSTILE_SESSION__', isTurnstileSessionVerified(req) ? 'verified' : 'required')
.replace('<div id="root"></div>', `<div id="root">\n${routeFallbackHtml(seo)}\n</div>`)
} }
function requestPathname(req) { function requestPathname(req) {