diff --git a/src/server/routes/note.ts b/src/server/routes/note.ts
--- a/src/server/routes/note.ts
+++ b/src/server/routes/note.ts
@@ -280,5 +280,6 @@ noteSlug,
noteTitle: data.note.title,
content: data.current.content,
sidebarNotes,
+ canonicalRecord: data.note,
});
});
diff --git a/src/server/routes/render-note.ts b/src/server/routes/render-note.ts
--- a/src/server/routes/render-note.ts
+++ b/src/server/routes/render-note.ts
@@ -7,7 +7,11 @@ import { noteUrl, resolvePublicUrl } from "../../lib/urls.ts";
import { resolveBookmarkHtml } from "../../views/bookmark.ts";
import { notePage } from "../../views/note.ts";
import { shareOnBlueskyButton } from "../../views/share.ts";
-import { wikiIdentity, wikiLayoutOptions } from "../../views/view-options.ts";
+import {
+ atCanonicalOption,
+ wikiIdentity,
+ wikiLayoutOptions,
+} from "../../views/view-options.ts";
interface NoteRenderInput {
ctx: WikiRequestContext;
@@ -17,6 +21,8 @@ noteTitle: string;
content: string;
sidebarNotes: { slug: string; title: string }[];
ogTitle?: string;
+ // The record this URL is the page for — the note, or the wiki on its home page.
+ canonicalRecord: { at_uri: string; did: string };
}
export function renderNoteResponse(input: NoteRenderInput): Response {
@@ -56,6 +62,7 @@ ogTitle: input.ogTitle ?? `${noteTitle} - ${ctx.wiki.name}`,
ogUrl: canonicalUrl,
ogImage,
...ogDescription,
+ ...atCanonicalOption(ctx.wiki, input.canonicalRecord),
},
ctx.wiki.language,
),
diff --git a/src/server/routes/wiki.ts b/src/server/routes/wiki.ts
--- a/src/server/routes/wiki.ts
+++ b/src/server/routes/wiki.ts
@@ -37,6 +37,7 @@ import { editSidebarPage } from "../../views/edit-sidebar.ts";
import { newWikiPage } from "../../views/new-wiki.ts";
import { settingsPage } from "../../views/settings.ts";
import {
+ atCanonicalOption,
baseLayoutOptions,
wikiIdentity,
wikiLayoutOptions,
@@ -402,6 +403,8 @@ noteTitle: homeData.note.title,
content: homeData.current.content,
sidebarNotes,
ogTitle: ctx.wiki.name,
+ // This URL is the wiki's page; the home note has its own.
+ canonicalRecord: ctx.wiki,
});
}
@@ -418,6 +421,7 @@ ogTitle: ctx.wiki.name,
ogUrl: `${publicUrl}${wikiUrl(handle, ctx.wiki.slug)}`,
ogImage,
...ogDescription,
+ ...atCanonicalOption(ctx.wiki, ctx.wiki),
},
ctx.wiki.language,
),
diff --git a/src/views/layout.ts b/src/views/layout.ts
--- a/src/views/layout.ts
+++ b/src/views/layout.ts
@@ -70,6 +70,8 @@ ogTitle?: string;
ogUrl?: string;
ogDescription?: string;
ogImage?: string;
+ // AT Tags: the record this URL is the page for. Set only for public wikis.
+ atCanonical?: { uri: string; authorDid: string };
wikiThemeMode?: WikiThemeMode;
wikiTheme?: ThemeName;
enableSearchShortcut?: boolean;
@@ -106,6 +108,17 @@
`;
+}
+
+// https://tangled.org/chrisshank.com/at-tags/ — the inverse of /at/:did/:collection/:rkey:
+// tells any atmosphere tool which record this page renders.
+function renderAtTags(options: LayoutOptions | undefined): string {
+ const record = options?.atCanonical;
+ if (!record) return "";
+ const uri = escapeHtml(record.uri);
+ return `
+
+ `;
}
function renderSearchButton(locale: Locale = "en"): string {
@@ -328,6 +341,7 @@ ${options?.noindex ? `` : ""}
${options?.csrfToken ? `` : ""}
${renderOpenGraph(options, title)}
+ ${renderAtTags(options)}