You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(web): technical SEO foundation for sqlritedb.com (SQLR-32) (#118)
- Per-route titles / descriptions / canonicals on / and /docs
- OpenGraph + Twitter cards (siteName, locale, summary_large_image)
restated at the page level since Next 15 shallow-merges these
- Auto-generated OG + Twitter images via next/og ImageResponse,
shared `OgFrame` JSX in src/lib/og.tsx; brand mark inlined as SVG
so Satori's dynamic-font fetcher doesn't 400 on the ▸ glyph
- app/sitemap.ts + app/robots.ts metadata routes; sitemap pointer
in robots and SITE.url canonical in both
- JSON-LD: SoftwareApplication on landing, BreadcrumbList on /docs
- Site-wide robots policy, keywords, author, and a placeholder
verification block in the root layout for GSC + Bing tokens
- Heading hierarchy: footer column h4→h3, /docs TOC h4→h2 (with
aria-label) so headings descend in order
- web/README.md SEO surface section documenting each piece
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: web/src/app/docs/page.tsx
+49-5Lines changed: 49 additions & 5 deletions
Original file line number
Diff line number
Diff line change
@@ -4,15 +4,59 @@ import { Footer } from "@/components/footer";
4
4
import{Nav}from"@/components/nav";
5
5
import{SITE}from"@/lib/site";
6
6
7
+
constTITLE="Getting started with SQLRite";
8
+
constDESCRIPTION=
9
+
"A ten-minute tour from cargo install to a persistent on-disk SQLRite database — REPL, transactions, JOINs, vector search, BM25 full-text, and six language SDKs.";
10
+
7
11
exportconstmetadata: Metadata={
8
-
title: "Getting started · SQLRite docs",
9
-
description:
10
-
"A ten-minute tour from cargo install to a persistent on-disk SQLRite database with real transactions, vector search, and full-text search.",
12
+
title: TITLE,
13
+
description: DESCRIPTION,
14
+
alternates: {canonical: "/docs"},
15
+
openGraph: {
16
+
type: "article",
17
+
siteName: "SQLRite",
18
+
locale: "en_US",
19
+
url: `${SITE.url}/docs`,
20
+
title: TITLE,
21
+
description: DESCRIPTION,
22
+
},
23
+
twitter: {
24
+
card: "summary_large_image",
25
+
site: SITE.twitterHandle,
26
+
creator: SITE.twitterHandle,
27
+
title: TITLE,
28
+
description: DESCRIPTION,
29
+
},
30
+
};
31
+
32
+
constbreadcrumbJsonLd={
33
+
"@context": "https://schema.org",
34
+
"@type": "BreadcrumbList",
35
+
itemListElement: [
36
+
{
37
+
"@type": "ListItem",
38
+
position: 1,
39
+
name: "Home",
40
+
item: SITE.url,
41
+
},
42
+
{
43
+
"@type": "ListItem",
44
+
position: 2,
45
+
name: "Docs",
46
+
item: `${SITE.url}/docs`,
47
+
},
48
+
],
11
49
};
12
50
13
51
exportdefaultfunctionDocsPage(){
14
52
return(
15
53
<>
54
+
<script
55
+
type="application/ld+json"
56
+
dangerouslySetInnerHTML={{
57
+
__html: JSON.stringify(breadcrumbJsonLd),
58
+
}}
59
+
/>
16
60
<Navvariant="docs"/>
17
61
<divclassName="docs-shell">
18
62
<asideclassName="docs-side">
@@ -733,8 +777,8 @@ export default function DocsPage() {
constDEFAULT_TITLE="SQLRite — embedded SQL database, built in Rust";
21
+
constDEFAULT_DESCRIPTION=
22
+
"An embedded SQL database modeled after SQLite, built from scratch in Rust. Single-file format, real B-tree, WAL, transactions, vector search, full-text search, and six language SDKs.";
23
+
19
24
exportconstmetadata: Metadata={
20
-
title: "SQLRite — embedded SQL database, built in Rust",
21
-
description:
22
-
"An embedded SQL database modeled after SQLite, built from scratch in Rust. Single-file format, real B-tree, WAL, transactions, vector search, full-text search, and six language SDKs.",
constTITLE="SQLRite — embedded SQL database, built in Rust";
17
+
constDESCRIPTION=
18
+
"Single-file embedded SQL engine in Rust. Real B-tree, WAL, transactions, JOINs, aggregates, HNSW vector search, BM25 full-text, plus six language SDKs.";
19
+
20
+
exportconstmetadata: Metadata={
21
+
title: {absolute: TITLE},
22
+
description: DESCRIPTION,
23
+
alternates: {canonical: "/"},
24
+
// openGraph and twitter aren't deep-merged with the parent layout in Next
25
+
// 15 — providing either at the page level fully replaces the layout's
26
+
// version, so site-wide fields (siteName, twitter card, etc.) have to be
27
+
// restated here.
28
+
openGraph: {
29
+
type: "website",
30
+
siteName: "SQLRite",
31
+
locale: "en_US",
32
+
url: SITE.url,
33
+
title: TITLE,
34
+
description: DESCRIPTION,
35
+
},
36
+
twitter: {
37
+
card: "summary_large_image",
38
+
site: SITE.twitterHandle,
39
+
creator: SITE.twitterHandle,
40
+
title: TITLE,
41
+
description: DESCRIPTION,
42
+
},
43
+
};
44
+
45
+
// JSON-LD describing SQLRite as a SoftwareApplication. Helps search engines
46
+
// surface a rich card (name + description + repo + license) and gives LLM
47
+
// crawlers a structured handle on what this project is.
48
+
constsoftwareApplicationJsonLd={
49
+
"@context": "https://schema.org",
50
+
"@type": "SoftwareApplication",
51
+
name: "SQLRite",
52
+
description: DESCRIPTION,
53
+
applicationCategory: "DeveloperApplication",
54
+
applicationSubCategory: "DatabaseApplication",
55
+
operatingSystem: "macOS, Windows, Linux, Web (WASM)",
56
+
softwareVersion: SITE.version,
57
+
url: SITE.url,
58
+
downloadUrl: SITE.releasesLatest,
59
+
codeRepository: SITE.repo,
60
+
programmingLanguage: "Rust",
61
+
license: "https://opensource.org/licenses/MIT",
62
+
offers: {
63
+
"@type": "Offer",
64
+
price: "0",
65
+
priceCurrency: "USD",
66
+
},
67
+
author: {
68
+
"@type": "Person",
69
+
name: "Joao Henrique Machado Silva",
70
+
url: SITE.socials.github,
71
+
},
72
+
};
13
73
14
74
exportdefaultfunctionHome(){
15
75
return(
16
76
<>
77
+
<script
78
+
type="application/ld+json"
79
+
// Stringified ahead of render — the script's content is static, so
80
+
// this is not a user-controlled injection vector.
0 commit comments