Wire branding into the app shell (todo §2); render config logo + default theme, fall back to the brand mark
This commit is contained in:
@@ -40,6 +40,17 @@ test("serves the home page: the app-shell People dashboard, filterable via the U
|
||||
assert.doesNotMatch(await empty.text(), /Avery Kline/);
|
||||
});
|
||||
|
||||
test("renders branding from the menu config into the shell: logo + default theme", async (t) => {
|
||||
const app = createApp({ menu: { branding: { logo: "/public/brand/logo.svg", name: "Acme Ops", theme: "dark" }, override: {} } });
|
||||
await new Promise<void>((r) => app.listen(0, r));
|
||||
t.after(() => app.close());
|
||||
const html = await (await fetch(`http://localhost:${(app.address() as AddressInfo).port}/`)).text();
|
||||
|
||||
assert.match(html, /<img class="brand-logo" src="\/public\/brand\/logo\.svg"/);
|
||||
assert.match(html, /Acme Ops/);
|
||||
assert.match(html, /id="theme-dark"\s+checked/); // config default theme reaches the switch
|
||||
});
|
||||
|
||||
test("serves a static file: GET sends body + content-type, HEAD sends headers only", async () => {
|
||||
const get = await fetch(base + "/public/css/styles.css");
|
||||
assert.equal(get.status, 200);
|
||||
|
||||
@@ -59,11 +59,12 @@ test("dashboard sorts by a column, reflects direction, and the header toggles",
|
||||
|
||||
test("dashboard applies the central menu config: branding + nav override (rename/hide)", () => {
|
||||
const m = buildDashboardModel(new URL("http://x/"), [], {
|
||||
branding: { name: "Acme Ops", sub: "Admin" },
|
||||
branding: { logo: "/public/logo.svg", name: "Acme Ops", sub: "Admin", theme: "dark" },
|
||||
override: { hide: ["teams"], rename: { people: "Staff" } },
|
||||
});
|
||||
|
||||
assert.deepEqual(m.shell.brand, { name: "Acme Ops", sub: "Admin" });
|
||||
assert.deepEqual(m.shell.brand, { logo: "/public/logo.svg", name: "Acme Ops", sub: "Admin" });
|
||||
assert.equal(m.shell.theme, "dark");
|
||||
const labels = m.nav.map((n) => n.label);
|
||||
assert.ok(labels.includes("Staff")); // "People" renamed
|
||||
assert.ok(!labels.includes("Teams")); // "Teams" hidden
|
||||
|
||||
@@ -106,8 +106,13 @@ export function buildDashboardModel(url: URL | URLSearchParams | string, roles:
|
||||
nav: nav(roles, menu.override),
|
||||
pagination: pagination(state, page),
|
||||
shell: {
|
||||
brand: { name: menu.branding.name, ...(menu.branding.sub != null ? { sub: menu.branding.sub } : {}) },
|
||||
brand: {
|
||||
...(menu.branding.logo != null ? { logo: menu.branding.logo } : {}),
|
||||
name: menu.branding.name,
|
||||
...(menu.branding.sub != null ? { sub: menu.branding.sub } : {}),
|
||||
},
|
||||
breadcrumbs: [{ href: "?", label: "Directory" }, { label: "People" }],
|
||||
...(menu.branding.theme != null ? { theme: menu.branding.theme } : {}),
|
||||
title: "People",
|
||||
user: { email: "sam.rivers@example.com", initials: "SR", name: "Sam Rivers" }, // demo until §4
|
||||
},
|
||||
|
||||
@@ -37,6 +37,17 @@ test("app shell renders sidebar, topbar and the content slot", async () => {
|
||||
assert.match(html, /<use href="#i-menu"\s*\/?>/); // hamburger references the menu icon
|
||||
});
|
||||
|
||||
test("app shell renders a configured logo + default theme, falls back to the brand mark", async () => {
|
||||
const branded = await render({ brand: { logo: "/public/brand/logo.svg", name: "Acme" }, theme: "dark" });
|
||||
assert.match(branded, /<img class="brand-logo" src="\/public\/brand\/logo\.svg"/);
|
||||
assert.doesNotMatch(branded, /brand-mark/); // a logo replaces the default mark
|
||||
assert.match(branded, /id="theme-dark"\s+checked/); // default theme applied to the switch
|
||||
|
||||
const plain = await render({ brand: { name: "Acme" } }); // no logo, no theme
|
||||
assert.match(plain, /<span class="brand-mark">/); // default mark
|
||||
assert.match(plain, /id="theme-auto"\s+checked/); // theme-switch default
|
||||
});
|
||||
|
||||
test("app shell escapes text but passes slot HTML through, and renders with defaults", async () => {
|
||||
const escaped = await render({ title: "<x>", body: "<p>raw</p>" });
|
||||
assert.match(escaped, /<title><x><\/title>/); // user text is escaped
|
||||
|
||||
Reference in New Issue
Block a user