diff --git a/web/src/app.d.ts b/web/src/app.d.ts index a708f0d8a..fbdefa38d 100644 --- a/web/src/app.d.ts +++ b/web/src/app.d.ts @@ -1,6 +1,15 @@ declare global { namespace App { interface PageData { + // per-page og overrides; the repo layout merges these over its + // repo-level defaults and renders the one + meta?: { + title?: string; + description?: string; + type?: "website" | "profile" | "article"; + image?: string; + noindex?: boolean; + }; publicConfig?: { bobbinUrl: string; knotMirrorUrl: string; diff --git a/web/src/lib/components/seo/PageHead.svelte b/web/src/lib/components/seo/PageHead.svelte deleted file mode 100644 index c7c2b8e97..000000000 --- a/web/src/lib/components/seo/PageHead.svelte +++ /dev/null @@ -1,40 +0,0 @@ - - - - {#if fullTitle} - {fullTitle} - - - {/if} - {#if description} - - - - {/if} - {#if type} - - {/if} - {#if noindex} - - {/if} - diff --git a/web/src/routes/[handle]/[repo]/+layout@.svelte b/web/src/routes/[handle]/[repo]/+layout@.svelte index 99c2906f8..cd5e80ede 100644 --- a/web/src/routes/[handle]/[repo]/+layout@.svelte +++ b/web/src/routes/[handle]/[repo]/+layout@.svelte @@ -89,6 +89,23 @@ }, ...(repoDesc ? { description: repoDesc } : {}) }); + // the repo-level og defaults; pages override fields (title, card, ...) by + // returning meta from their load, which lands here through page data + const og = $derived({ + title: repoTitle, + description: repoDescription, + image: + resolvedRepo || repoMeta + ? repoCard( + (resolvedRepo || repoMeta)!, + resolvedCounts, + data.publicConfig?.ogreUrl, + ogLanguages + ) + : undefined, + noindex: false, + ...page.data.meta + }); const isCustomOgChildRoute = $derived( (page.route.id ?? "").includes("/issues/[aturi]") || @@ -157,18 +174,13 @@ {#if !isCustomOgChildRoute} {/if} diff --git a/web/src/routes/[handle]/[repo]/commit/[ref]/+page.svelte b/web/src/routes/[handle]/[repo]/commit/[ref]/+page.svelte index 2934fb935..c77aef50e 100644 --- a/web/src/routes/[handle]/[repo]/commit/[ref]/+page.svelte +++ b/web/src/routes/[handle]/[repo]/commit/[ref]/+page.svelte @@ -10,7 +10,6 @@ import repoCommitviewFullCommit from "$lib/bones/repo-commitview--full-commit.bones.json"; import CommitView from "$lib/components/repo/CommitView.svelte"; import Pending from "$lib/components/ui/Pending.svelte"; - import PageHead from "$lib/components/seo/PageHead.svelte"; import type { DiffStyle } from "$lib/components/repo/pierre"; let { data } = $props(); @@ -22,7 +21,6 @@ const synchronousRepo = $derived(data.repo instanceof Promise ? null : data.repo); let asyncRepo = $state(null); let asyncCommitPage = $state | null>(null); - let asyncAuthor = $state | null>(null); $effect(() => { let active = true; @@ -32,9 +30,6 @@ void Promise.resolve(data.commitPage).then((cp) => { if (active) asyncCommitPage = cp; }); - void Promise.resolve(data.author).then((a) => { - if (active) asyncAuthor = a; - }); return () => { active = false; }; @@ -42,20 +37,6 @@ const resolvedRepo = $derived(asyncRepo ?? synchronousRepo); const repoName = $derived(resolvedRepo?.name ?? decodeURIComponent(page.params.repo ?? "")); - const commitSummary = $derived( - asyncCommitPage?.commit?.subject || `Commit ${data.ref.slice(0, 8)}` - ); - const commitTitle = $derived(`${commitSummary} · ${repoName} · Tangled`); - const authorLabel = $derived( - asyncAuthor?.handle - ? `@${asyncAuthor.handle}` - : asyncCommitPage?.commit?.authorName || "Unknown author" - ); - const commitBodyText = $derived(asyncCommitPage?.commit?.body?.trim()); - const commitDesc = $derived( - `${commitSummary} by ${authorLabel}${commitBodyText ? ` — ${commitBodyText.replace(/\s+/g, " ").slice(0, 100)}` : ""}` - ); - const pipelineStatuses = liveCommitStatuses(() => Promise.all([data.repo, data.commitPage]).then(([repo, commitPage]) => ({ repo, @@ -64,8 +45,6 @@ ); - - {#snippet skeleton()} diff --git a/web/src/routes/[handle]/[repo]/commit/[ref]/+page.ts b/web/src/routes/[handle]/[repo]/commit/[ref]/+page.ts index 1996b482c..4edd4c0e7 100644 --- a/web/src/routes/[handle]/[repo]/commit/[ref]/+page.ts +++ b/web/src/routes/[handle]/[repo]/commit/[ref]/+page.ts @@ -113,6 +113,11 @@ export const load: PageLoad = async (event) => { return settle({ ref: event.params.ref, commitPage: stream(commitPage), - author: stream(authorPromise) + author: stream(authorPromise), + meta: { + title: `Commit ${event.params.ref.slice(0, 8)} · ${event.params.repo} · Tangled`, + description: `Commit ${event.params.ref.slice(0, 8)} in ${event.params.repo} on Tangled.`, + type: "article" as const + } }); }; diff --git a/web/src/routes/[handle]/[repo]/fork/+page.svelte b/web/src/routes/[handle]/[repo]/fork/+page.svelte index 737e7d909..07cdde19f 100644 --- a/web/src/routes/[handle]/[repo]/fork/+page.svelte +++ b/web/src/routes/[handle]/[repo]/fork/+page.svelte @@ -1,5 +1,4 @@ - - {#snippet skeleton()} diff --git a/web/src/routes/[handle]/[repo]/fork/+page.ts b/web/src/routes/[handle]/[repo]/fork/+page.ts index 5d0e47c7a..9afb5dc8e 100644 --- a/web/src/routes/[handle]/[repo]/fork/+page.ts +++ b/web/src/routes/[handle]/[repo]/fork/+page.ts @@ -4,5 +4,10 @@ import type { PageLoad } from "./$types"; export const load: PageLoad = async (event) => { const parent = await event.parent(); - return settle(await repoCreationOptions(parent, event.fetch)); + const handle = decodeURIComponent(event.params.handle ?? ""); + const repo = decodeURIComponent(event.params.repo ?? ""); + return settle({ + ...(await repoCreationOptions(parent, event.fetch)), + meta: { noindex: true, title: `Fork · ${handle}/${repo}` } + }); }; diff --git a/web/src/routes/[handle]/[repo]/issues/new/+page.svelte b/web/src/routes/[handle]/[repo]/issues/new/+page.svelte index 0d17d0766..0d637f0f5 100644 --- a/web/src/routes/[handle]/[repo]/issues/new/+page.svelte +++ b/web/src/routes/[handle]/[repo]/issues/new/+page.svelte @@ -1,5 +1,4 @@ - -

Create a new issue

diff --git a/web/src/routes/[handle]/[repo]/issues/new/+page.ts b/web/src/routes/[handle]/[repo]/issues/new/+page.ts new file mode 100644 index 000000000..265daab3d --- /dev/null +++ b/web/src/routes/[handle]/[repo]/issues/new/+page.ts @@ -0,0 +1,9 @@ +import type { PageLoad } from "./$types"; + +export const load: PageLoad = async (event) => { + const handle = decodeURIComponent(event.params.handle ?? ""); + const repo = decodeURIComponent(event.params.repo ?? ""); + return { + meta: { noindex: true, title: `New issue · ${handle}/${repo}` } + }; +}; diff --git a/web/src/routes/[handle]/[repo]/pulls/new/+page.svelte b/web/src/routes/[handle]/[repo]/pulls/new/+page.svelte index c4519802e..1f2765ab8 100644 --- a/web/src/routes/[handle]/[repo]/pulls/new/+page.svelte +++ b/web/src/routes/[handle]/[repo]/pulls/new/+page.svelte @@ -1,5 +1,4 @@ - - {#snippet skeleton()} diff --git a/web/src/routes/[handle]/[repo]/pulls/new/+page.ts b/web/src/routes/[handle]/[repo]/pulls/new/+page.ts index c420eb0ca..791550987 100644 --- a/web/src/routes/[handle]/[repo]/pulls/new/+page.ts +++ b/web/src/routes/[handle]/[repo]/pulls/new/+page.ts @@ -5,6 +5,8 @@ import type { PageLoad } from "./$types"; export const load: PageLoad = async (event) => { const parent = await event.parent(); const repo = Promise.resolve(parent.repo); + const handle = decodeURIComponent(event.params.handle ?? ""); + const name = decodeURIComponent(event.params.repo ?? ""); return settle({ compose: stream( @@ -15,6 +17,7 @@ export const load: PageLoad = async (event) => { params: event.url.searchParams, fetch: event.fetch }) - ) + ), + meta: { noindex: true, title: `New pull · ${handle}/${name}` } }); }; diff --git a/web/src/routes/[handle]/[repo]/tree/[ref]/[...path]/+page.svelte b/web/src/routes/[handle]/[repo]/tree/[ref]/[...path]/+page.svelte index 0d06b4e5c..067feab15 100644 --- a/web/src/routes/[handle]/[repo]/tree/[ref]/[...path]/+page.svelte +++ b/web/src/routes/[handle]/[repo]/tree/[ref]/[...path]/+page.svelte @@ -9,7 +9,6 @@ import bonesTreeviewSkeletonFixture from "$lib/bones/bones-treeview--skeleton-fixture.bones.json"; import TreeHeader from "$lib/components/repo/TreeHeader.svelte"; import Pending from "$lib/components/ui/Pending.svelte"; - import PageHead from "$lib/components/seo/PageHead.svelte"; import TabPanel from "$lib/components/ui/TabPanel.svelte"; let { data } = $props(); @@ -29,13 +28,8 @@ const resolvedRepo = $derived(asyncRepo ?? synchronousRepo); const repoName = $derived(resolvedRepo?.name ?? decodeURIComponent(page.params.repo ?? "")); - const filePath = $derived(data.path); - const treeTitle = $derived(`${filePath} · ${repoName} · Tangled`); - const treeDesc = $derived(`Viewing ${filePath} in ${repoName} on Tangled.`); - - {#snippet skeleton()} diff --git a/web/src/routes/[handle]/[repo]/tree/[ref]/[...path]/+page.ts b/web/src/routes/[handle]/[repo]/tree/[ref]/[...path]/+page.ts index 1c73a3353..62a35ada1 100644 --- a/web/src/routes/[handle]/[repo]/tree/[ref]/[...path]/+page.ts +++ b/web/src/routes/[handle]/[repo]/tree/[ref]/[...path]/+page.ts @@ -5,5 +5,11 @@ import type { PageLoad } from "./$types"; // the rest param arrives decoded and joined, so it is the path as git knows it export const load: PageLoad = async (event) => { const parent = await event.parent(); - return settle(await loadRepoTree(event, parent, event.params.ref, event.params.path)); + return settle({ + ...(await loadRepoTree(event, parent, event.params.ref, event.params.path)), + meta: { + title: `${event.params.path} · ${event.params.repo} · Tangled`, + description: `Viewing ${event.params.path} in ${event.params.repo} on Tangled.` + } + }); };