diff --git a/AGENTS.md b/AGENTS.md index 0217604..cdf9e70 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -168,6 +168,14 @@ them. Revisit only if the stated reason stops holding. workspace dir, so ci.sh's web-image build races another run's container creation on the `-web` tag. Accepted for a single-maintainer cadence; serialize with a workflow `concurrency` group if it ever bites. +- **`ICON_NAMES` (`src/ui/icons.ts`) is a host-owned registry, not a frozen plugin contract.** It is + deliberately not re-exported from `#plugin-api`, and README → Nav & permission gates already tells an + author that using a new icon means registering it there. So the palette may narrow when the last + reference to an id goes — `i-gear` left with the settings menu 2026-08-05 — and a plugin needing one + gets it re-registered in the same change. Accepted cost: an unknown sprite id renders a blank icon + instead of failing loud; the `every icon resolves to a defined ` e2e test catches it for + anything reaching the nav. Removing an id is a core edit, so weigh it per icon rather than sweeping the + registry — a few ids are registered ahead of a caller (see `todo.md`). ## Docker only — no host tooling diff --git a/e2e-tests/visual.spec.ts b/e2e-tests/visual.spec.ts index 244337c..5edcf83 100644 --- a/e2e-tests/visual.spec.ts +++ b/e2e-tests/visual.spec.ts @@ -101,7 +101,7 @@ test("the public landing at / is ungated and links to sign in + register", async await expect(page.locator(".landing")).toBeVisible(); // the same app shell every page renders — the menu shows even signed out (permission-filtered). await expect(page.locator(".sidebar")).toBeVisible(); - await expect(page.locator('.side-footer use[href="#i-gear"]')).toHaveCount(0); // no settings cog to offer a signed-out visitor + await expect(page.locator('use[href="#i-gear"]')).toHaveCount(0); // no settings cog to offer a signed-out visitor await expect(page.getByRole("link", { name: "Log in" })).toHaveAttribute("href", "/login"); await expect(page.getByRole("link", { name: "Create account" })).toHaveAttribute("href", "/registration"); await shot(page, "live-05-public-landing"); diff --git a/public/css/styles.css b/public/css/styles.css index 989d810..9cb0e5f 100644 --- a/public/css/styles.css +++ b/public/css/styles.css @@ -282,7 +282,6 @@ span.nav-self { cursor: default; } /* static / non-clickable */ outline: 2px solid var(--focus); outline-offset: 1px; } -/* profile row */ .footer-actions { display: flex; align-items: center; gap: 4px; } .profile { display: flex; align-items: center; gap: 9px; flex: 1 1 auto; diff --git a/src/ui/shell.test.ts b/src/ui/shell.test.ts index af47c2b..68c0877 100644 --- a/src/ui/shell.test.ts +++ b/src/ui/shell.test.ts @@ -40,9 +40,6 @@ test("app shell renders sidebar, topbar and the content slot", async () => { assert.match(html, /