fix(website): SEO canonicals, host redirects, sitemap, app noindex
Addresses the high-volume issues from the Ahrefs audit: - Worker entrypoint 301s every request not on https://paseo.sh (www subdomain and http variants), killing the duplicate-page errors and the HTTP→HTTPS internal-link notices. - pageMeta() emits <link rel="canonical"> and og:url per route; every head() call now passes its canonical path. - /blog stops rewriting itself to /blog?drafts=false; the search param only appears when explicitly true. - Sitemap includes /blog and each post. - Trim homepage title under SERP truncation, rewrite /agents meta description under 160 chars, pad short descriptions on /privacy, /download, /cloud, /changelog, /docs. - app.paseo.sh gets <meta robots=noindex,nofollow> and a Disallow-all robots.txt so the SPA shell stops polluting the crawl with H1-missing / no-OG / low-word-count warnings.
This commit is contained in:
@@ -6,11 +6,10 @@ import { pageMeta } from "~/meta";
|
||||
export const Route = createFileRoute("/blog/$")({
|
||||
head: ({ params }) => {
|
||||
const slug = params._splat ?? "";
|
||||
const path = `/blog/${slug}`;
|
||||
const post = getPost(slug);
|
||||
if (!post) return { meta: pageMeta("Not Found - Paseo", "Post not found.") };
|
||||
return {
|
||||
meta: pageMeta(`${post.frontmatter.title} - Paseo`, post.frontmatter.description),
|
||||
};
|
||||
if (!post) return pageMeta("Not Found - Paseo", "Post not found.", path);
|
||||
return pageMeta(`${post.frontmatter.title} - Paseo`, post.frontmatter.description, path);
|
||||
},
|
||||
component: BlogPost,
|
||||
});
|
||||
|
||||
@@ -3,13 +3,21 @@ import { createFileRoute, Link } from "@tanstack/react-router";
|
||||
import { getPosts, formatDate } from "~/posts";
|
||||
import { pageMeta } from "~/meta";
|
||||
|
||||
interface BlogSearch {
|
||||
drafts?: true;
|
||||
}
|
||||
|
||||
export const Route = createFileRoute("/blog/")({
|
||||
validateSearch: (search: Record<string, unknown>) => ({
|
||||
drafts: search.drafts === true || search.drafts === "" || search.drafts === "true",
|
||||
}),
|
||||
head: () => ({
|
||||
meta: pageMeta("Blog - Paseo", "Updates, thoughts, and announcements from the Paseo team."),
|
||||
}),
|
||||
validateSearch: (search: Record<string, unknown>): BlogSearch => {
|
||||
const drafts = search.drafts === true || search.drafts === "" || search.drafts === "true";
|
||||
return drafts ? { drafts: true } : {};
|
||||
},
|
||||
head: () =>
|
||||
pageMeta(
|
||||
"Blog – Updates and announcements from the Paseo team",
|
||||
"Product updates, technical posts, and announcements from the Paseo team. Notes on building a self-hosted, multi-agent dev environment for your phone.",
|
||||
"/blog",
|
||||
),
|
||||
component: BlogIndex,
|
||||
});
|
||||
|
||||
@@ -43,7 +51,7 @@ function PostRow({ slug, title, date, draft }: PostRowProps) {
|
||||
|
||||
function BlogIndex() {
|
||||
const { drafts } = Route.useSearch();
|
||||
const posts = getPosts(drafts);
|
||||
const posts = getPosts(drafts === true);
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
Reference in New Issue
Block a user