feat(ui): icons for the mobile side-nav items
Crop / fingerprint-recognition / logout Carbon icons (16px, inlined into the shared header so they inherit the theme colour) in the side-nav-link 'title-icon' slot — the slot is named title-icon, not nav-icon.
This commit is contained in:
+12
-5
@@ -119,8 +119,8 @@ function esc(value) {
|
|||||||
const appHeader = (session, active) => {
|
const appHeader = (session, active) => {
|
||||||
const toolLink = (href, label, key) =>
|
const toolLink = (href, label, key) =>
|
||||||
`<cds-header-nav-item href="${href}"${key === active ? ' aria-current="page"' : ''}>${label}</cds-header-nav-item>`;
|
`<cds-header-nav-item href="${href}"${key === active ? ' aria-current="page"' : ''}>${label}</cds-header-nav-item>`;
|
||||||
const sideLink = (href, label, key) =>
|
const sideLink = (href, label, key, icon) =>
|
||||||
`<cds-side-nav-link href="${href}"${key === active ? ' aria-current="page"' : ''}>${label}</cds-side-nav-link>`;
|
`<cds-side-nav-link href="${href}"${key === active ? ' aria-current="page"' : ''}>${icon || ''}${label}</cds-side-nav-link>`;
|
||||||
const name = session ? (session.firstName || session.phone || '') : '';
|
const name = session ? (session.firstName || session.phone || '') : '';
|
||||||
const right = session
|
const right = session
|
||||||
? `<span class="user-chip"><span class="avatar">${esc(name.trim().slice(0, 2).toUpperCase())}</span>${esc(name)}</span>
|
? `<span class="user-chip"><span class="avatar">${esc(name.trim().slice(0, 2).toUpperCase())}</span>${esc(name)}</span>
|
||||||
@@ -145,10 +145,10 @@ const appHeader = (session, active) => {
|
|||||||
<span>YOUreka Tools</span>
|
<span>YOUreka Tools</span>
|
||||||
</div>
|
</div>
|
||||||
<cds-side-nav-items>
|
<cds-side-nav-items>
|
||||||
${sideLink('/cropper', 'Image Cropper', 'cropper')}
|
${sideLink('/cropper', 'Image Cropper', 'cropper', SIDE_NAV_ICONS.crop)}
|
||||||
${sideLink('/fingerprint', 'Fingerprint Agent', 'fingerprint')}
|
${sideLink('/fingerprint', 'Fingerprint Agent', 'fingerprint', SIDE_NAV_ICONS.fingerprint)}
|
||||||
<cds-side-nav-divider></cds-side-nav-divider>
|
<cds-side-nav-divider></cds-side-nav-divider>
|
||||||
<cds-side-nav-link href="/auth/logout" data-signout>Sign out</cds-side-nav-link>
|
<cds-side-nav-link href="/auth/logout" data-signout>${SIDE_NAV_ICONS.logout}Sign out</cds-side-nav-link>
|
||||||
</cds-side-nav-items>
|
</cds-side-nav-items>
|
||||||
</cds-side-nav>
|
</cds-side-nav>
|
||||||
<cds-modal id="signout-modal" size="xs" aria-label="Sign out of YOUreka Tools">
|
<cds-modal id="signout-modal" size="xs" aria-label="Sign out of YOUreka Tools">
|
||||||
@@ -187,6 +187,13 @@ const appHeader = (session, active) => {
|
|||||||
`;
|
`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Carbon icons for the mobile side nav (inlined so they inherit the theme). */
|
||||||
|
const SIDE_NAV_ICONS = {
|
||||||
|
crop: '<svg slot="title-icon" width="16" height="16" fill="currentColor" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M25,20H23V9H12V7H23a2,2,0,0,1,2,2Z"/><path d="M9,23V2H7V7H2V9H7V23a2,2,0,0,0,2,2H23v5h2V25h5V23Z"/></svg>',
|
||||||
|
fingerprint: '<svg slot="title-icon" width="16" height="16" fill="currentColor" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M7,5.21a.77.77,0,0,1-.46-1.38A15.46,15.46,0,0,1,16,1c2.66,0,6.48.45,9.5,2.62a.77.77,0,0,1,.18,1.07.78.78,0,0,1-1.08.17A15,15,0,0,0,16,2.53,14,14,0,0,0,7.5,5.05.74.74,0,0,1,7,5.21Z"/><path d="M28.23,12.26a.78.78,0,0,1-.63-.33C25.87,9.49,22.78,6.24,16,6.24a14,14,0,0,0-11.63,5.7.77.77,0,0,1-1.07.17A.76.76,0,0,1,3.15,11,15.54,15.54,0,0,1,16,4.71c5.61,0,9.81,2.08,12.84,6.34a.77.77,0,0,1-.19,1.07A.79.79,0,0,1,28.23,12.26Z"/><path d="M12.28,31a.78.78,0,0,1-.72-.49.75.75,0,0,1,.44-1c4.37-1.68,7-5.12,7-9.21a2.8,2.8,0,0,0-3-3c-1.86,0-2.76,1-3,3.35a4.27,4.27,0,0,1-4.52,3.83,4.27,4.27,0,0,1-4.32-4.59A11.71,11.71,0,0,1,16,8.39a12,12,0,0,1,12,11.93,18.66,18.66,0,0,1-1.39,6.5.78.78,0,0,1-1,.41.76.76,0,0,1-.41-1,17.25,17.25,0,0,0,1.27-5.91A10.45,10.45,0,0,0,16,9.92a10.18,10.18,0,0,0-10.38,10,2.77,2.77,0,0,0,2.79,3.06,2.74,2.74,0,0,0,3-2.48c.36-3.11,1.89-4.69,4.56-4.69a4.31,4.31,0,0,1,4.52,4.56c0,4.74-3,8.72-8,10.63A.92.92,0,0,1,12.28,31Z"/><path d="M19.77,30.28a.81.81,0,0,1-.52-.2.76.76,0,0,1,0-1.08,12.63,12.63,0,0,0,3.54-8.68c0-1.56-.48-6.65-6.7-6.65a6.83,6.83,0,0,0-4.94,1.87A6.17,6.17,0,0,0,9.32,20a.77.77,0,0,1-.77.76h0A.76.76,0,0,1,7.78,20,7.73,7.73,0,0,1,10,14.46a8.34,8.34,0,0,1,6-2.32c6.08,0,8.24,4.4,8.24,8.18A14.09,14.09,0,0,1,20.34,30,.75.75,0,0,1,19.77,30.28Z"/><path d="M8.66,27.74a14.14,14.14,0,0,1-1.56-.09.76.76,0,1,1,.17-1.52c2.49.28,4.45-.16,5.84-1.32a6.37,6.37,0,0,0,2.12-4.53.75.75,0,0,1,.82-.71.78.78,0,0,1,.72.81A7.89,7.89,0,0,1,14.09,26,8.2,8.2,0,0,1,8.66,27.74Z"/></svg>',
|
||||||
|
logout: '<svg slot="title-icon" width="16" height="16" fill="currentColor" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M6,30H18a2.0023,2.0023,0,0,0,2-2V25H18v3H6V4H18V7h2V4a2.0023,2.0023,0,0,0-2-2H6A2.0023,2.0023,0,0,0,4,4V28A2.0023,2.0023,0,0,0,6,30Z"/><path d="M20.586 20.586L24.172 17 10 17 10 15 24.172 15 20.586 11.414 22 10 28 16 22 22 20.586 20.586z"/></svg>',
|
||||||
|
};
|
||||||
|
|
||||||
// ── app factory ──────────────────────────────────────────────────────────────
|
// ── app factory ──────────────────────────────────────────────────────────────
|
||||||
export function createApp(overrides = {}) {
|
export function createApp(overrides = {}) {
|
||||||
const cfg = {
|
const cfg = {
|
||||||
|
|||||||
@@ -355,6 +355,10 @@ test('landing header is server-rendered for the session', async () => {
|
|||||||
assert.match(anon, /cds-header-nav-item href="\/fingerprint"/);
|
assert.match(anon, /cds-header-nav-item href="\/fingerprint"/);
|
||||||
assert.match(anon, /cds-side-nav-link href="\/cropper"/);
|
assert.match(anon, /cds-side-nav-link href="\/cropper"/);
|
||||||
assert.match(anon, /cds-side-nav-divider/);
|
assert.match(anon, /cds-side-nav-divider/);
|
||||||
|
// side nav items carry Carbon icons in the title-icon slot
|
||||||
|
assert.match(anon, /cds-side-nav-link href="\/cropper"[^>]*><svg slot="title-icon"/);
|
||||||
|
assert.match(anon, /cds-side-nav-link href="\/fingerprint"[^>]*><svg slot="title-icon"/);
|
||||||
|
assert.match(anon, /cds-side-nav-link href="\/auth\/logout"[^>]*><svg slot="title-icon"/);
|
||||||
assert.match(anon, /cds-side-nav-link href="\/auth\/logout"/);
|
assert.match(anon, /cds-side-nav-link href="\/auth\/logout"/);
|
||||||
assert.match(anon, /youreka-logo\.png/);
|
assert.match(anon, /youreka-logo\.png/);
|
||||||
assert.match(anon, /header-menu-button/);
|
assert.match(anon, /header-menu-button/);
|
||||||
|
|||||||
Reference in New Issue
Block a user