feat(ui): Youreka favicon, logout confirmation, nav active states, brand alignment

- favicon is the Youreka logo (64px PNG generated from the source mark),
  on the tools pages and server error pages
- signing out asks first: a Carbon cds-modal (Cancel / danger Sign out)
  shared by the header and the mobile side nav; Cancel closes, Sign out
  confirms and logs out
- the current tool is now visibly selected: Carbon marks active nav via
  a[aria-current=page] INSIDE the shadow, but aria-current sits on the
  host, so the rule never matched — the header item now gets a blue
  underline and the side-nav link a blue left border (via ::part(link)
  for colour, plus the host for the marker)
- logo and wordmark are middle-aligned inside a flex brand wrapper
- tests: favicon/modal/signout-trigger markup and the active-tool marking
  on both navs (45 total)
This commit is contained in:
2026-10-01 04:08:09 +01:00
parent 17c407883d
commit 2e4a51d018
7 changed files with 83 additions and 8 deletions
+40 -3
View File
@@ -73,6 +73,10 @@ function errorPage(res, status, title, message, actions = {}) {
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>${esc(title)} · YOUreka Tools</title>
<link rel="stylesheet" href="/assets/style.css">
<link rel="icon" type="image/png" href="/assets/youreka-favicon.png">
<script type="module" src="https://1.www.s81c.com/common/carbon/web-components/version/v2.50.0/modal.min.js"></script>
<script type="module" src="https://1.www.s81c.com/common/carbon/web-components/version/v2.50.0/ui-shell.min.js"></script>
<script type="module" src="https://1.www.s81c.com/common/carbon/web-components/version/v2.50.0/tag.min.js"></script>
</head>
<body class="app cds--g100">
${appHeader(null, null)}
@@ -120,13 +124,13 @@ const appHeader = (session, active) => {
const name = session ? (session.firstName || session.phone || '') : '';
const right = session
? `<span class="user-chip"><span class="avatar">${esc(name.trim().slice(0, 2).toUpperCase())}</span>${esc(name)}</span>
<a class="linklike" href="/auth/logout">Sign out</a>`
<a class="linklike" href="/auth/logout" data-signout>Sign out</a>`
: '<a class="linklike" href="/auth/login">Sign in</a>';
return `
<cds-header aria-label="YOUreka Tools">
<cds-header-menu-button button-label-active="Close menu" button-label-inactive="Open menu" id="header-menu-button"></cds-header-menu-button>
<cds-header-name href="/">
<span class="brand-logo"><img src="/assets/youreka-logo.png" alt="" width="20" height="20"></span>YOUreka<span class="brand-suffix"> Tools</span>
<span class="brand-inner"><span class="brand-logo"><img src="/assets/youreka-logo.png" alt="" width="20" height="20"></span><span>YOUreka<span class="brand-suffix"> Tools</span></span></span>
</cds-header-name>
<cds-header-nav>
${toolLink('/cropper', 'Image Cropper', 'cropper')}
@@ -144,9 +148,42 @@ const appHeader = (session, active) => {
${sideLink('/cropper', 'Image Cropper', 'cropper')}
${sideLink('/fingerprint', 'Fingerprint Agent', 'fingerprint')}
<cds-side-nav-divider></cds-side-nav-divider>
<cds-side-nav-link href="/auth/logout">Sign out</cds-side-nav-link>
<cds-side-nav-link href="/auth/logout" data-signout>Sign out</cds-side-nav-link>
</cds-side-nav-items>
</cds-side-nav>
<cds-modal id="signout-modal" size="xs" aria-label="Sign out of YOUreka Tools">
<cds-modal-header>
<cds-modal-close-button></cds-modal-close-button>
<cds-modal-label>Account</cds-modal-label>
<cds-modal-heading>Sign out of YOUreka Tools?</cds-modal-heading>
</cds-modal-header>
<cds-modal-body>You will need to authenticate again to use the tools.</cds-modal-body>
<cds-modal-footer>
<cds-modal-footer-button kind="secondary" data-modal-close>Cancel</cds-modal-footer-button>
<cds-modal-footer-button kind="danger" id="signout-confirm">Sign out</cds-modal-footer-button>
</cds-modal-footer>
</cds-modal>
<script>
// Confirm before signing out (Carbon modal)
(function () {
function wire() {
var modal = document.getElementById('signout-modal');
var confirm = document.getElementById('signout-confirm');
if (!modal || !confirm) return;
document.addEventListener('click', function (event) {
var trigger = event.target && event.target.closest ? event.target.closest('[data-signout]') : null;
if (!trigger) return;
event.preventDefault();
modal.open = true;
});
confirm.addEventListener('click', function () {
window.location.href = '/auth/logout';
});
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', wire);
else wire();
})();
</script>
`;
};