From 3917170a16d4758e84c440279fda6f55fd693c99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Baldur=20P=C3=A1ll=20H=C3=B3lmgeirsson?= Date: Sun, 18 Oct 2026 19:32:09 +0000 Subject: [PATCH 1/3] docs(site): replace the navbar avatar with the Northguild logo Phase 1 of #104. The navbar rendered the northguild GitHub org avatar, hotlinked from github.com. It now renders the supplied shield artwork from docs/src/assets/logo.svg via a static import, so Next applies the /worktree basePath and content-hashes the file. The circular crop is dropped (the shield is 1000x1317) and the height stays at 32px. The footer keeps the avatar (D2), and site-meta.ts and its generator are untouched (D3). Navbar.test.tsx now pins the image source to the asset; pointing the navbar back at the avatar URL fails the new test. Gate 1: pnpm check, typecheck, build, test (1006) and docs:test (69) all exit 0, and the test-marker grep is clean. A production docs build with a dummy GEMINI_WORKER_URL serves the logo at /worktree/_next/static/media/logo..svg. Gate 2: reviewer subagent, PASS WITH NOTES, nothing blocking; the notes are in context/notes.md. --- context/notes.md | 19 +++++++++++++++++++ docs/src/assets/logo.svg | 7 +++++++ docs/src/components/Navbar.test.tsx | 18 ++++++++++++++---- docs/src/components/Navbar.tsx | 14 +++++--------- 4 files changed, 45 insertions(+), 13 deletions(-) create mode 100644 context/notes.md create mode 100644 docs/src/assets/logo.svg diff --git a/context/notes.md b/context/notes.md new file mode 100644 index 0000000..59b81ab --- /dev/null +++ b/context/notes.md @@ -0,0 +1,19 @@ +# Notes + +Branch-local and advisory. Nothing reads this file, and `/feature-close` deletes it. + +## Phase 1 — Swap the navbar logo for a repository asset (Gate 2, PASS WITH NOTES) + +- **Dark theme.** The shield's outer fill `#184165` is roughly 1.8:1 against Nextra's near-black navbar + (estimated from the SVG's colours, not a rendered page). The inner marks stand out, but the shield outline + barely shows. The image is decorative and the artwork was supplied, so nothing fails; a dark-theme + variant or a light outline would be an artwork change. +- `docs/src/assets/logo.svg` carries `role="img" aria-label="Northguild logo"`. These attributes do nothing + through ``, and would only matter if the SVG were ever inlined. +- `logo` is typed `any` by Next's ambient `*.svg` declaration (`next/image-types/global`). No code here + wrote `any`. +- `Navbar.test.tsx` still finds the image with `getByTestId`, which `react/testing.md` calls a last resort. + It is unchanged from before, since the `next/image` mock renders a `` that no role query matches. +- The new `data-src` test can tell the logo from the avatar only because Vitest loads the SVG as a URL + string. A test setup that loaded it as Next's `StaticImageData` object would make both sides + `"[object Object]"`, and the test would pass whatever the source was. diff --git a/docs/src/assets/logo.svg b/docs/src/assets/logo.svg new file mode 100644 index 0000000..28131a5 --- /dev/null +++ b/docs/src/assets/logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/docs/src/components/Navbar.test.tsx b/docs/src/components/Navbar.test.tsx index 450aa1a..132f332 100644 --- a/docs/src/components/Navbar.test.tsx +++ b/docs/src/components/Navbar.test.tsx @@ -1,6 +1,7 @@ import { render, screen } from "@testing-library/react"; import type { ReactNode } from "react"; import { vi } from "vitest"; +import logo from "../assets/logo.svg"; import { Navbar } from "./Navbar"; type MockNavbarProps = { @@ -9,8 +10,8 @@ type MockNavbarProps = { }; vi.mock("next/image", () => ({ - default: ({ alt }: { alt?: string }) => ( - + default: ({ alt, src }: { alt?: string; src?: string }) => ( + ), })); @@ -59,11 +60,20 @@ describe("Navbar", () => { expect(home).toHaveTextContent("Worktree"); }); - it("does not nest a link inside the logo and treats the avatar as decorative", () => { + it("does not nest a link inside the home link and treats the logo image as decorative", () => { render(); const home = screen.getByRole("link", { name: "Worktree home page" }); expect(home.querySelectorAll("a")).toHaveLength(0); - expect(screen.getByTestId("avatar")).toHaveAttribute("data-alt", ""); + expect(screen.getByTestId("logo")).toHaveAttribute("data-alt", ""); + }); + + it("renders the repository logo asset, not the organisation avatar", () => { + render(); + + expect(screen.getByTestId("logo")).toHaveAttribute( + "data-src", + String(logo), + ); }); }); diff --git a/docs/src/components/Navbar.tsx b/docs/src/components/Navbar.tsx index d13a39a..b8151d1 100644 --- a/docs/src/components/Navbar.tsx +++ b/docs/src/components/Navbar.tsx @@ -1,16 +1,13 @@ import Image from "next/image"; import Link from "next/link"; import { Navbar as NextraNavbar } from "nextra-theme-docs"; -import { - projectLink, - projectName, - projectOwnerAvatarUrl, -} from "../lib/site-meta"; +import logo from "../assets/logo.svg"; +import { projectLink, projectName } from "../lib/site-meta"; // Nextra's own logo link is disabled (`logoLink={false}`) because its fixed // aria-label "Home page" does not contain the visible text "Worktree" (WCAG // 2.5.3). The logo is instead a next/link to "/", which applies the production -// basePath. The avatar is decorative (alt=""); the link's name starts with the +// basePath. The logo is decorative (alt=""); the link's name starts with the // visible text and says where it goes. The utility classes are the ones // Nextra's logo link uses, for the keyboard focus ring and hover affordance. export function Navbar() { @@ -30,11 +27,10 @@ export function Navbar() { }} > {projectName} From 5e06e42b498970dc7d6b249977e9fc876974d943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Baldur=20P=C3=A1ll=20H=C3=B3lmgeirsson?= Date: Sun, 18 Oct 2026 19:44:22 +0000 Subject: [PATCH 2/3] chore(context): retire docs-site-logo Deletes the branch-local context/notes.md, per /feature-close. #104's plan and ledger stay in the issue, which this branch's pull request closes. --- context/notes.md | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 context/notes.md diff --git a/context/notes.md b/context/notes.md deleted file mode 100644 index 59b81ab..0000000 --- a/context/notes.md +++ /dev/null @@ -1,19 +0,0 @@ -# Notes - -Branch-local and advisory. Nothing reads this file, and `/feature-close` deletes it. - -## Phase 1 — Swap the navbar logo for a repository asset (Gate 2, PASS WITH NOTES) - -- **Dark theme.** The shield's outer fill `#184165` is roughly 1.8:1 against Nextra's near-black navbar - (estimated from the SVG's colours, not a rendered page). The inner marks stand out, but the shield outline - barely shows. The image is decorative and the artwork was supplied, so nothing fails; a dark-theme - variant or a light outline would be an artwork change. -- `docs/src/assets/logo.svg` carries `role="img" aria-label="Northguild logo"`. These attributes do nothing - through ``, and would only matter if the SVG were ever inlined. -- `logo` is typed `any` by Next's ambient `*.svg` declaration (`next/image-types/global`). No code here - wrote `any`. -- `Navbar.test.tsx` still finds the image with `getByTestId`, which `react/testing.md` calls a last resort. - It is unchanged from before, since the `next/image` mock renders a `` that no role query matches. -- The new `data-src` test can tell the logo from the avatar only because Vitest loads the SVG as a URL - string. A test setup that loaded it as Next's `StaticImageData` object would make both sides - `"[object Object]"`, and the test would pass whatever the source was. From 86c024d86bd54a2ce2eeaad7a0c32b2a5c9444cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Baldur=20P=C3=A1ll=20H=C3=B3lmgeirsson?= Date: Mon, 19 Oct 2026 12:25:12 +0000 Subject: [PATCH 3/3] docs(site): address review on the navbar logo From the review on #106: - Size the logo with height={32} alone. The 2rem style overrode it and only agreed with it at a 16px root font size. Next derives the width from the SVG's 1000x1317 aspect ratio. - Drop role="img" and aria-label from logo.svg. Through they were inert, and if the SVG were ever inlined they would add "Northguild logo" to the home link's name (WCAG 2.5.3). - Check that the logo test's src is an SVG, an inlined data URI or a .svg path, before comparing it with the import. If the import were ever a stringified StaticImageData object, both sides would equal "[object Object]" and the comparison would pass. The new assertion uses no jest-dom matcher, so the docs tsc count is back to main's 5 for this file. Gate 1: pnpm check, typecheck, build, test (1006) and docs:test (69) all exit 0. Pointing the navbar back at the avatar URL, or passing an object src, fails the test. A production docs build serves /worktree/_next/static/media/logo..svg. --- docs/src/assets/logo.svg | 2 +- docs/src/components/Navbar.test.tsx | 10 ++++++---- docs/src/components/Navbar.tsx | 7 +------ 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/docs/src/assets/logo.svg b/docs/src/assets/logo.svg index 28131a5..63a0172 100644 --- a/docs/src/assets/logo.svg +++ b/docs/src/assets/logo.svg @@ -1,4 +1,4 @@ - + diff --git a/docs/src/components/Navbar.test.tsx b/docs/src/components/Navbar.test.tsx index 132f332..07e6dcf 100644 --- a/docs/src/components/Navbar.test.tsx +++ b/docs/src/components/Navbar.test.tsx @@ -71,9 +71,11 @@ describe("Navbar", () => { it("renders the repository logo asset, not the organisation avatar", () => { render(); - expect(screen.getByTestId("logo")).toHaveAttribute( - "data-src", - String(logo), - ); + // Vitest inlines the SVG as a data URI where Next would give a hashed path; + // either way it must be an SVG, which rules out the avatar and a stringified + // StaticImageData object that would make the equality below vacuous. + const src = screen.getByTestId("logo").getAttribute("data-src"); + expect(src).toMatch(/^data:image\/svg\+xml,|\.svg$/); + expect(src).toBe(String(logo)); }); }); diff --git a/docs/src/components/Navbar.tsx b/docs/src/components/Navbar.tsx index b8151d1..1de813b 100644 --- a/docs/src/components/Navbar.tsx +++ b/docs/src/components/Navbar.tsx @@ -26,12 +26,7 @@ export function Navbar() { gap: "0.5rem", }} > - + {projectName} }