From a8cbcd60e8de1e12c117b3bf2cbd0c680742ae9f Mon Sep 17 00:00:00 2001 From: CodeMash Date: Sat, 3 Oct 2026 11:13:52 +0300 Subject: [PATCH 1/6] [1] docs(admin:branding): task file for project name and logo in the portal Co-Authored-By: Claude Opus 5.5 --- docs/tasks/project-branding.md | 38 ++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 docs/tasks/project-branding.md diff --git a/docs/tasks/project-branding.md b/docs/tasks/project-branding.md new file mode 100644 index 0000000..46cc767 --- /dev/null +++ b/docs/tasks/project-branding.md @@ -0,0 +1,38 @@ +# Project branding — the Admin Portal shows the project's name and logo + +Item C of the Norbix "Project" coverage campaign. Branch `audit/project-branding` +(admin repo, from `origin/main`). + +## Goal + +The portal shell, every sign-in screen and the browser tab show the project's +name and logo (from the gateway's public config) instead of "Account", +"Norbix" or "Admin Portal". + +Not in scope: new branding fields on the gateway, dark mode, a mobile header +(the portal has none today — see Findings), the colour tokens (already applied). + +## Plan + +1. docs(admin:branding): this task file — done +2. feat(admin:branding): `AppLayout` sidebar header shows the logo (alt = name) or the project name; every `AuthLayout` use passes `brandName` + `logoUrl` from the store; `Placeholder` keeps "Norbix Admin" (no project is known there — see Findings) — todo +3. feat(admin:branding): `applyBranding` sets `document.title` to the project name; static metadata `Admin Portal` stays as the pre-load fallback — todo +4. test(admin:branding): vitest — `loadDynamicConfig` mapping (name fallback order, branding absent / present), `applyBranding` (title, favicon, CSS variables) — todo +5. test(admin:branding): fake host returns a branding block with a logo the fake host serves itself; `tests/e2e/branding.spec.ts` + goldens — todo +6. chore(admin:branding): typecheck, lint, format:check, vitest, Playwright fake-host suite all green; push; pull request — todo + +## Changes + +| file | what changed | plan step # | +|------|--------------|-------------| +| `docs/tasks/project-branding.md` | this file | 1 | + +## Findings + +## Rejected / moved out + +## Needs you + +## Open questions + +None. From c1241f028d2a11013a71fac3b8a3e0b05cee0f10 Mon Sep 17 00:00:00 2001 From: CodeMash Date: Sat, 3 Oct 2026 11:15:23 +0300 Subject: [PATCH 2/6] [2-3] feat(admin:branding): project logo or name in the sidebar, brand on every auth screen, tab title = project name Co-Authored-By: Claude Opus 5.5 --- src/components/layouts.tsx | 23 ++++++++++++++++++++--- src/config/projectConfig.ts | 24 ++++++++++++++++++++++-- src/features/auth/callback.tsx | 6 ++++-- src/features/auth/passwordReset.tsx | 8 ++++++-- 4 files changed, 52 insertions(+), 9 deletions(-) diff --git a/src/components/layouts.tsx b/src/components/layouts.tsx index 457a6a1..3c50948 100644 --- a/src/components/layouts.tsx +++ b/src/components/layouts.tsx @@ -13,7 +13,9 @@ import { } from './icons'; import { DropdownMenu } from './ui'; import { ROUTES } from '@/routes'; -import { useAppDispatch } from '@/app/hooks'; +import { useAppDispatch, useAppSelector } from '@/app/hooks'; +import { selectProjectBranding } from '@/features/project/slice'; +import { projectNameOf } from '@/config/projectConfig'; import { reset } from '@/features/auth/slice'; import { useLogoutMutation } from '@/services/norbix'; import { AiChatLauncher } from '@/features/aiChat/launcher'; @@ -57,6 +59,9 @@ export function AppLayout({ children }: { children: ReactNode }) { const dispatch = useAppDispatch(); const navigate = useNavigate(); const [logout] = useLogoutMutation(); + const branding = useAppSelector(selectProjectBranding); + const projectName = projectNameOf(branding); + const logoUrl = branding?.logoUrl; const handleSignOut = async () => { try { @@ -71,8 +76,20 @@ export function AppLayout({ children }: { children: ReactNode }) { return (