From 672b831f8c356ea3b008f30ac8650ec0d7c39d52 Mon Sep 17 00:00:00 2001 From: lilleman Date: Mon, 15 Jun 2026 11:51:44 +0200 Subject: [PATCH] =?UTF-8?q?Add=20app-shell=20partial=20(todo=20=C2=A71);?= =?UTF-8?q?=20sidebar=20+=20topbar=20+=20content/nav=20slots,=20reuses=20m?= =?UTF-8?q?ockup=20classes=20+=20icon=20sprite?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/shell.test.ts | 44 +++++++++++++++++++ todo.md | 2 +- views/partials/shell.ejs | 92 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 src/shell.test.ts create mode 100644 views/partials/shell.ejs diff --git a/README.md b/README.md index 4830f78..57b1b41 100644 --- a/README.md +++ b/README.md @@ -362,7 +362,7 @@ src/context.ts RequestContext handed to handlers + buildContext() src/config.ts Env loader — Ory endpoints, cookie/CSRF secrets, JWKS, port; validated at boot src/icons.ts Used-icon registry + sprite builder from lucide-static (regenerates partials/icons.ejs) src/plugin.ts definePlugin() + the host's plugin discovery/router (planned) -views/ Core EJS templates (index, 403/404/500, partials/ incl. the icon sprite) +views/ Core EJS templates (index, 403/404/500, partials/ incl. the app shell + icon sprite) public/ Static assets under /public/ (css/styles.css + auth.css, favicon, robots.txt) config/menu.ts Central menu override + branding (planned) plugins/ Drop-in plugin folders, auto-discovered (planned) diff --git a/src/shell.test.ts b/src/shell.test.ts new file mode 100644 index 0000000..54d143d --- /dev/null +++ b/src/shell.test.ts @@ -0,0 +1,44 @@ +import assert from "node:assert/strict"; +import { dirname, join } from "node:path"; +import { test } from "node:test"; +import { fileURLToPath } from "node:url"; +import * as ejs from "ejs"; + +const shell = join(dirname(fileURLToPath(import.meta.url)), "..", "views", "partials", "shell.ejs"); +const render = (data: Record = {}): Promise => ejs.renderFile(shell, data); + +test("app shell renders sidebar, topbar and the content slot", async () => { + const html = await render({ + title: "People", + brand: { name: "Acme Console", sub: "v2" }, + nav: 'Overview', + body: '
page
', + actions: '', + }); + + // Three structural landmarks of the shell. + assert.match(html, / + + + + +
+
+ +
<%= title %>
+ <% if (breadcrumbs.length) { %> + + <% } %> +
+ <%- actions %> +
+ + <%- body %> +
+ + +