Polish results, FPP, and auth UI
This commit is contained in:
59
server.js
59
server.js
@@ -687,7 +687,7 @@ function renderResultsTable(results, selectedResultId) {
|
|||||||
(result) => `
|
(result) => `
|
||||||
<tr>
|
<tr>
|
||||||
<td><strong>${escapeHtml(result.patient)}</strong><br /><span class="muted">${escapeHtml(result.summary)}</span></td>
|
<td><strong>${escapeHtml(result.patient)}</strong><br /><span class="muted">${escapeHtml(result.summary)}</span></td>
|
||||||
<td><a href="/results/${result.id}">${escapeHtml(result.id)}</a></td>
|
<td><a href="/results/${result.id}" hx-get="/fragments/results/detail/${result.id}" hx-target="#result-detail-fragment" hx-swap="innerHTML">${escapeHtml(result.id)}</a></td>
|
||||||
<td>${escapeHtml(result.test)}</td>
|
<td>${escapeHtml(result.test)}</td>
|
||||||
<td>${statusBadge(result.status)}</td>
|
<td>${statusBadge(result.status)}</td>
|
||||||
<td>${escapeHtml(result.date)}</td>
|
<td>${escapeHtml(result.date)}</td>
|
||||||
@@ -710,6 +710,8 @@ function renderResultsTable(results, selectedResultId) {
|
|||||||
</div>
|
</div>
|
||||||
${statusBadge(result.status)}
|
${statusBadge(result.status)}
|
||||||
</div>
|
</div>
|
||||||
|
<div style="height:12px"></div>
|
||||||
|
<a class="btn btn-secondary" href="/results/${result.id}" hx-get="/fragments/results/detail/${result.id}" hx-target="#result-detail-fragment" hx-swap="innerHTML">Open detail</a>
|
||||||
<p class="muted" style="margin-top:10px">${escapeHtml(result.summary)}</p>
|
<p class="muted" style="margin-top:10px">${escapeHtml(result.summary)}</p>
|
||||||
</article>
|
</article>
|
||||||
`,
|
`,
|
||||||
@@ -717,7 +719,7 @@ function renderResultsTable(results, selectedResultId) {
|
|||||||
.join("")}
|
.join("")}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<aside class="panel">
|
<aside class="panel" id="result-detail-fragment">
|
||||||
${panelHeader("Selected result", "Use the right pane for quick context without losing list position.", `<a class="btn btn-secondary" href="/results/${selected.id}">Open detail</a>`)}
|
${panelHeader("Selected result", "Use the right pane for quick context without losing list position.", `<a class="btn btn-secondary" href="/results/${selected.id}">Open detail</a>`)}
|
||||||
<div class="stack">
|
<div class="stack">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
@@ -766,7 +768,20 @@ function renderFpp(groups) {
|
|||||||
${panelHeader("FPP catalog", "Filter blocks and list cards on mobile, richer panel on desktop.")}
|
${panelHeader("FPP catalog", "Filter blocks and list cards on mobile, richer panel on desktop.")}
|
||||||
<div class="pill-row">
|
<div class="pill-row">
|
||||||
${["All", ...mockFppGroups.map((item) => item.group)]
|
${["All", ...mockFppGroups.map((item) => item.group)]
|
||||||
.map((item) => `<a class="pill ${groups.filter === item ? "active" : ""}" href="/fragments/fpp/list?group=${encodeURIComponent(item)}">${escapeHtml(item)}</a>`)
|
.map(
|
||||||
|
(item) => `
|
||||||
|
<button
|
||||||
|
class="pill ${groups.filter === item ? "active" : ""}"
|
||||||
|
type="button"
|
||||||
|
hx-get="/fragments/fpp/list?group=${encodeURIComponent(item)}"
|
||||||
|
hx-target="#fpp-fragment"
|
||||||
|
hx-swap="innerHTML"
|
||||||
|
hx-push-url="true"
|
||||||
|
>
|
||||||
|
${escapeHtml(item)}
|
||||||
|
</button>
|
||||||
|
`,
|
||||||
|
)
|
||||||
.join("")}
|
.join("")}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -916,12 +931,21 @@ function loginPage({ error = "" } = {}) {
|
|||||||
<section class="auth-card">
|
<section class="auth-card">
|
||||||
<div class="auth-visual">
|
<div class="auth-visual">
|
||||||
<div class="badge">DocLink rebuild · responsive shell</div>
|
<div class="badge">DocLink rebuild · responsive shell</div>
|
||||||
<h1>Clinical workflow that works on desktop and mobile.</h1>
|
<h1>Clinical workflow that stays fast on desktop and mobile.</h1>
|
||||||
<p>The old app behavior is preserved in a cleaner layout with dashboard, orders, results, FPP, and settings routes.</p>
|
<p>The rebuilt shell keeps the old app's workflows intact, but removes the cramped mobile-only feel.</p>
|
||||||
|
<div class="auth-highlight">
|
||||||
|
<strong>Built for doctors who move between screens</strong>
|
||||||
|
<span>Orders, results, FPP, and account actions stay one click away.</span>
|
||||||
|
</div>
|
||||||
<div class="auth-points">
|
<div class="auth-points">
|
||||||
<div class="auth-point"><strong>Route structure</strong><div>Login, dashboard, order flow, result flow, and account pages.</div></div>
|
|
||||||
<div class="auth-point"><strong>Responsive shell</strong><div>Persistent sidebar on desktop, bottom nav on mobile.</div></div>
|
<div class="auth-point"><strong>Responsive shell</strong><div>Persistent sidebar on desktop, bottom nav on mobile.</div></div>
|
||||||
<div class="auth-point"><strong>Clean interaction model</strong><div>HTMX fragments plus server-rendered templates.</div></div>
|
<div class="auth-point"><strong>HTMX fragments</strong><div>Detail panels update without leaving the page.</div></div>
|
||||||
|
<div class="auth-point"><strong>API adapter</strong><div>Login, orders, results, and save flows proxy upstream.</div></div>
|
||||||
|
</div>
|
||||||
|
<div class="auth-mini-grid">
|
||||||
|
<div class="auth-mini-card"><strong>5 routes</strong><span>Public + shell</span></div>
|
||||||
|
<div class="auth-mini-card"><strong>3 flows</strong><span>Most used actions</span></div>
|
||||||
|
<div class="auth-mini-card"><strong>1 session</strong><span>Cookie-backed auth</span></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="auth-form">
|
<div class="auth-form">
|
||||||
@@ -940,6 +964,7 @@ function loginPage({ error = "" } = {}) {
|
|||||||
<div class="pill-row">
|
<div class="pill-row">
|
||||||
<a class="pill" href="/splash">Open splash</a>
|
<a class="pill" href="/splash">Open splash</a>
|
||||||
<a class="pill" href="/problem-login">Problem login</a>
|
<a class="pill" href="/problem-login">Problem login</a>
|
||||||
|
<span class="pill">Demo fallback ready</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -958,12 +983,20 @@ function splashPage() {
|
|||||||
<div class="auth-visual">
|
<div class="auth-visual">
|
||||||
<div class="badge">Starting DocLink</div>
|
<div class="badge">Starting DocLink</div>
|
||||||
<h1>Loading workspace...</h1>
|
<h1>Loading workspace...</h1>
|
||||||
<p>Checking session and routing into the right entry point.</p>
|
<p>Checking session state, then routing into the right clinical entry point.</p>
|
||||||
|
<div class="auth-highlight">
|
||||||
|
<strong>Fast redirect</strong>
|
||||||
|
<span>Users land on dashboard, login, or the error screen without extra clicks.</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="auth-form">
|
<div class="auth-form">
|
||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
<strong>Redirecting</strong>
|
<strong>Redirecting</strong>
|
||||||
<p>We will move you to the correct route in a moment.</p>
|
<p>We will move you to the correct route in a moment.</p>
|
||||||
|
<div class="pill-row" style="justify-content:center; margin-top:14px">
|
||||||
|
<span class="pill">Session check</span>
|
||||||
|
<span class="pill">Route resolve</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -982,7 +1015,11 @@ function problemLoginPage() {
|
|||||||
<div class="auth-visual">
|
<div class="auth-visual">
|
||||||
<div class="badge">Login problem</div>
|
<div class="badge">Login problem</div>
|
||||||
<h1>Access needs attention.</h1>
|
<h1>Access needs attention.</h1>
|
||||||
<p>Use this page when auth state is broken or a session expires.</p>
|
<p>Use this page when auth state is broken, expired, or the upstream login rejects credentials.</p>
|
||||||
|
<div class="auth-highlight">
|
||||||
|
<strong>What to do</strong>
|
||||||
|
<span>Re-enter credentials or wait for the upstream service to recover.</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="auth-form">
|
<div class="auth-form">
|
||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
@@ -990,6 +1027,10 @@ function problemLoginPage() {
|
|||||||
<p>The session was cleared. Go back to login and sign in again.</p>
|
<p>The session was cleared. Go back to login and sign in again.</p>
|
||||||
<div style="height:16px"></div>
|
<div style="height:16px"></div>
|
||||||
<a class="btn btn-primary" href="/login">Back to login</a>
|
<a class="btn btn-primary" href="/login">Back to login</a>
|
||||||
|
<div class="pill-row" style="justify-content:center; margin-top:14px">
|
||||||
|
<span class="pill">Auth reset</span>
|
||||||
|
<span class="pill">Retry login</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
54
styles.css
54
styles.css
@@ -734,6 +734,52 @@ tr:last-child td {
|
|||||||
gap: 18px;
|
gap: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.auth-highlight {
|
||||||
|
display: grid;
|
||||||
|
gap: 6px;
|
||||||
|
margin-top: 18px;
|
||||||
|
padding: 16px 18px;
|
||||||
|
border-radius: 18px;
|
||||||
|
color: #effaf8;
|
||||||
|
background: rgba(255, 255, 255, 0.12);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.14);
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-highlight strong {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-highlight span {
|
||||||
|
line-height: 1.55;
|
||||||
|
opacity: 0.94;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-mini-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-mini-card {
|
||||||
|
padding: 14px 15px;
|
||||||
|
border-radius: 18px;
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-mini-card strong {
|
||||||
|
display: block;
|
||||||
|
font-size: 1.05rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-mini-card span {
|
||||||
|
display: block;
|
||||||
|
margin-top: 4px;
|
||||||
|
opacity: 0.86;
|
||||||
|
font-size: 0.88rem;
|
||||||
|
}
|
||||||
|
|
||||||
.auth-form h2 {
|
.auth-form h2 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 1.9rem;
|
font-size: 1.9rem;
|
||||||
@@ -823,6 +869,10 @@ tr:last-child td {
|
|||||||
box-shadow: var(--shadow-lg);
|
box-shadow: var(--shadow-lg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal-card .panel-header {
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
.desktop-only {
|
.desktop-only {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
@@ -908,6 +958,10 @@ tr:last-child td {
|
|||||||
max-height: 100vh;
|
max-height: 100vh;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.auth-mini-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 620px) {
|
@media (max-width: 620px) {
|
||||||
|
|||||||
Reference in New Issue
Block a user