fix(ui): session-aware landing header, clickable tiles, shell padding and spacing

- .container redefined on Carbon tokens (was Bootstrap's class — pages had
  no edge padding after the Bootstrap removal)
- landing tiles use cds-clickable-tile and — critically — matching closing
  tags: the fingerprint tile was parsed as NESTED inside the cropper tile
  (mismatched </cds-tile>), painting it on top and swallowing clicks
- landing header reflects the active session (user chip + Sign out instead
  of Sign in)
- vertical rhythm: larger panel padding, row gaps and section margins
This commit is contained in:
2026-10-01 02:52:40 +01:00
parent 930af97f05
commit 76009efb86
2 changed files with 36 additions and 17 deletions
+15 -11
View File
@@ -18,10 +18,13 @@ body.app {
/* prevent FOUC on web components */ /* prevent FOUC on web components */
cds-button:not(:defined), cds-tag:not(:defined), cds-tile:not(:defined), cds-button:not(:defined), cds-tag:not(:defined), cds-tile:not(:defined),
cds-inline-notification:not(:defined), cds-toast:not(:defined), cds-clickable-tile:not(:defined), cds-inline-notification:not(:defined),
cds-toast-item:not(:defined), cds-progress-bar:not(:defined) { cds-toast:not(:defined), cds-toast-item:not(:defined), cds-progress-bar:not(:defined) {
visibility: hidden; visibility: hidden;
} }
/* Carbon styles the shadow anchor inside tiles, not the host — give the host
a real box so grid columns and click targets work correctly. */
cds-tile, cds-clickable-tile { display: block; }
/* ── header (Carbon ui-shell look) ──────────────────────────────────────── */ /* ── header (Carbon ui-shell look) ──────────────────────────────────────── */
.nav { .nav {
@@ -52,12 +55,11 @@ cds-toast-item:not(:defined), cds-progress-bar:not(:defined) {
} }
/* ── layout ─────────────────────────────────────────────────────────────── */ /* ── layout ─────────────────────────────────────────────────────────────── */
main.container { flex: 1 0 auto; max-width: none; padding: 0 1rem; width: 100%; } .container { width: 100%; max-width: 1136px; margin: 0 auto; padding: 0 1.5rem; }
main.container > * { max-width: 1136px; margin-left: auto; margin-right: auto; } main.container { flex: 1 0 auto; padding-top: 1.5rem; padding-bottom: 1.5rem; }
main.container > .narrow { max-width: 560px; }
.narrow { max-width: 560px; } .narrow { max-width: 560px; }
.center-v { display: flex; flex-direction: column; justify-content: center; min-height: 70vh; } .center-v { display: flex; flex-direction: column; justify-content: center; min-height: 70vh; }
.page-head { margin: 2rem auto 1.25rem; display: flex; align-items: flex-end; justify-content: space-between; gap: 1rem; flex-wrap: wrap; } .page-head { margin: 1.5rem auto 1.5rem; display: flex; align-items: flex-end; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
.page-head h1 { font-size: 1.5rem; font-weight: 600; margin: 0; letter-spacing: 0; } .page-head h1 { font-size: 1.5rem; font-weight: 600; margin: 0; letter-spacing: 0; }
.page-head .sub { color: var(--cds-text-secondary, #525252); margin: 0.25rem 0 0; font-size: 14px; } .page-head .sub { color: var(--cds-text-secondary, #525252); margin: 0.25rem 0 0; font-size: 14px; }
@@ -67,7 +69,7 @@ main.container > .narrow { max-width: 560px; }
border: 1px solid var(--cds-border-subtle, #c6c6c6); border: 1px solid var(--cds-border-subtle, #c6c6c6);
border-radius: 2px; border-radius: 2px;
} }
.panel { padding: 1.25rem 1.5rem 1.5rem; margin-bottom: 1rem; } .panel { padding: 1.5rem 1.75rem 1.75rem; margin-bottom: 1.25rem; }
.panel-head { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 1rem; flex-wrap: wrap; } .panel-head { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 1rem; flex-wrap: wrap; }
.step-chip { .step-chip {
width: 22px; height: 22px; border-radius: 2px; flex: 0 0 auto; width: 22px; height: 22px; border-radius: 2px; flex: 0 0 auto;
@@ -82,7 +84,8 @@ main.container > .narrow { max-width: 560px; }
.hero { padding: 2.5rem 0 1.75rem; } .hero { padding: 2.5rem 0 1.75rem; }
.hero h1 { font-size: 1.75rem; font-weight: 600; margin: 0 0 0.35rem; } .hero h1 { font-size: 1.75rem; font-weight: 600; margin: 0 0 0.35rem; }
.hero p { color: var(--cds-text-secondary, #525252); max-width: 560px; margin: 0; font-size: 14px; } .hero p { color: var(--cds-text-secondary, #525252); max-width: 560px; margin: 0; font-size: 14px; }
.tool-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1rem; max-width: 960px; } .tool-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem; max-width: 960px; }
@media (max-width: 720px) { .tool-grid { grid-template-columns: 1fr; } }
.tool-grid cds-tile { height: 100%; } .tool-grid cds-tile { height: 100%; }
.tool-card { display: flex; flex-direction: column; padding: 1.25rem; } .tool-card { display: flex; flex-direction: column; padding: 1.25rem; }
.tool-card h3 { font-size: 1rem; font-weight: 600; margin: 0.75rem 0 0.3rem; } .tool-card h3 { font-size: 1rem; font-weight: 600; margin: 0.75rem 0 0.3rem; }
@@ -134,10 +137,11 @@ cds-button::part(button) { font-size: 14px; }
/* ── badges → cds-tag; helper text ──────────────────────────────────────── */ /* ── badges → cds-tag; helper text ──────────────────────────────────────── */
.faint { color: var(--cds-text-helper, #6f6f6f); font-size: 12px; } .faint { color: var(--cds-text-helper, #6f6f6f); font-size: 12px; }
.muted { color: var(--cds-text-secondary, #525252); } .muted { color: var(--cds-text-secondary, #525252); }
.mt-1 { margin-top: 0.75rem; } .mt-1 { margin-top: 1rem; }
.mt-2 { margin-top: 1.25rem; } .mt-2 { margin-top: 1.5rem; }
.row-gap { display: flex; gap: 0.75rem; align-items: center; flex-wrap: wrap; } .row-gap { display: flex; gap: 1rem; align-items: center; flex-wrap: wrap; }
.flex-fill { flex: 1 1 auto; } .flex-fill { flex: 1 1 auto; }
.form-field { margin-bottom: 0.25rem; }
/* ── details grid ───────────────────────────────────────────────────────── */ /* ── details grid ───────────────────────────────────────────────────────── */
.details { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 0.9rem 1.4rem; margin: 0 0 0.25rem; } .details { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 0.9rem 1.4rem; margin: 0 0 0.25rem; }
+21 -6
View File
@@ -10,7 +10,7 @@
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><rect width='24' height='24' rx='4' fill='%230f62fe'/><path d='M12 5a6 6 0 0 0-6 6c0 2.6.8 4.1 1.5 5.2' fill='none' stroke='white' stroke-width='1.6' stroke-linecap='round'/><path d='M15.5 19a7.5 7.5 0 0 0 3-9.7A6 6 0 0 0 7.1 7.9' fill='none' stroke='white' stroke-width='1.6' stroke-linecap='round'/><path d='M9.5 18.5a5.5 5.5 0 0 1-.8-7.6 3.8 3.8 0 0 1 7.2 1.5 4.3 4.3 0 0 1-3.4 4.6' fill='none' stroke='white' stroke-width='1.6' stroke-linecap='round'/></svg>"> <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><rect width='24' height='24' rx='4' fill='%230f62fe'/><path d='M12 5a6 6 0 0 0-6 6c0 2.6.8 4.1 1.5 5.2' fill='none' stroke='white' stroke-width='1.6' stroke-linecap='round'/><path d='M15.5 19a7.5 7.5 0 0 0 3-9.7A6 6 0 0 0 7.1 7.9' fill='none' stroke='white' stroke-width='1.6' stroke-linecap='round'/><path d='M9.5 18.5a5.5 5.5 0 0 1-.8-7.6 3.8 3.8 0 0 1 7.2 1.5 4.3 4.3 0 0 1-3.4 4.6' fill='none' stroke='white' stroke-width='1.6' stroke-linecap='round'/></svg>">
<script type="module" src="https://1.www.s81c.com/common/carbon/web-components/version/v2.50.0/tile.min.js"></script> <script type="module" src="https://1.www.s81c.com/common/carbon/web-components/version/v2.50.0/tile.min.js"></script>
<style> <style>
cds-tile:not(:defined) { visibility: hidden; } cds-tile:not(:defined), cds-clickable-tile:not(:defined) { visibility: hidden; }
</style> </style>
</head> </head>
<body class="app"> <body class="app">
@@ -22,7 +22,7 @@
</span> </span>
YOUreka <small>Tools</small> YOUreka <small>Tools</small>
</a> </a>
<div class="nav-right"> <div class="nav-right" id="nav-session">
<a class="linklike" href="/auth/login">Sign in</a> <a class="linklike" href="/auth/login">Sign in</a>
</div> </div>
</div> </div>
@@ -35,7 +35,7 @@
</div> </div>
<div class="tool-grid"> <div class="tool-grid">
<cds-tile href="/cropper"> <cds-clickable-tile href="/cropper">
<div class="tool-card"> <div class="tool-card">
<span class="tool-icon"> <span class="tool-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 2v14a2 2 0 0 0 2 2h14"/><path d="M18 22V8a2 2 0 0 0-2-2H2"/></svg> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 2v14a2 2 0 0 0 2 2h14"/><path d="M18 22V8a2 2 0 0 0-2-2H2"/></svg>
@@ -46,9 +46,9 @@
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg> <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg>
</span> </span>
</div> </div>
</cds-tile> </cds-clickable-tile>
<cds-tile href="/fingerprint"> <cds-clickable-tile href="/fingerprint">
<div class="tool-card"> <div class="tool-card">
<span class="tool-icon"> <span class="tool-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 2a8 8 0 0 0-8 8c0 3.5 1 5.5 2 7"/><path d="M16 21a10 10 0 0 0 4-13 8 8 0 0 0-15.7-1"/><path d="M8 21a8 8 0 0 1-1-11 5 5 0 0 1 9.7 1.4A6 6 0 0 1 12 17"/><path d="M12 21a4 4 0 0 0 4-4 4 4 0 0 0-1.2-2.9"/></svg> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 2a8 8 0 0 0-8 8c0 3.5 1 5.5 2 7"/><path d="M16 21a10 10 0 0 0 4-13 8 8 0 0 0-15.7-1"/><path d="M8 21a8 8 0 0 1-1-11 5 5 0 0 1 9.7 1.4A6 6 0 0 1 12 17"/><path d="M12 21a4 4 0 0 0 4-4 4 4 0 0 0-1.2-2.9"/></svg>
@@ -59,7 +59,7 @@
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg> <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg>
</span> </span>
</div> </div>
</cds-tile> </cds-clickable-tile>
</div> </div>
</main> </main>
@@ -69,5 +69,20 @@
<span>Scan captures run locally via the fpagent agent &mdash; no scanner data leaves this machine except the enrolled artifacts you save.</span> <span>Scan captures run locally via the fpagent agent &mdash; no scanner data leaves this machine except the enrolled artifacts you save.</span>
</div> </div>
</footer> </footer>
<script>
// Reflect the current session in the header: Sign in vs user chip + Sign out.
fetch('/auth/session')
.then(function (r) { return r.ok ? r.json() : null; })
.then(function (session) {
var host = document.getElementById('nav-session');
if (!session) return; // keep the Sign in link
var first = (session.firstName || session.phone || '?').trim();
host.innerHTML =
'<span class="user-chip"><span class="avatar">' + first.slice(0, 2).toUpperCase() + '</span>' +
(session.firstName || session.phone) + '</span>' +
'<a class="linklike" href="/auth/logout">Sign out</a>';
})
.catch(function () { /* keep Sign in */ });
</script>
</body> </body>
</html> </html>