v1.4 - Login fixes, etc

This commit is contained in:
2026-04-27 21:53:36 +12:00
parent 8cf9bfb441
commit c9580ac2eb
33 changed files with 2283 additions and 202 deletions
+157 -14
View File
@@ -1,7 +1,6 @@
<script lang="ts">
import { invalidateAll } from '$app/navigation';
import { api } from '$lib/api';
import { clientSession } from '$lib/session';
import { clientSession, sessionHydrated } from '$lib/session';
import type { Mix, ProductCostBreakdown, RawMaterial } from '$lib/types';
type Segment = {
@@ -42,7 +41,6 @@
try {
const session = await api.clientLogin(email, password);
clientSession.set(session);
await invalidateAll();
} catch (error) {
loginError = error instanceof Error ? error.message : 'Unable to sign in';
} finally {
@@ -253,7 +251,23 @@
const focusCards = $derived(buildFocusCards());
</script>
{#if !$clientSession}
{#if !$sessionHydrated}
<section class="dashboard-intro">
<div>
<p class="eyebrow">Client Workspace</p>
<h2>Restoring your workspace.</h2>
<p>Checking the saved client session before deciding whether sign-in is required.</p>
</div>
</section>
<section class="workspace-banner login-banner loading-banner">
<div>
<p class="eyebrow">Checking Session</p>
<h3>Hold while the app restores your client access state.</h3>
<p>The sign-in form only appears if no valid local session is available.</p>
</div>
</section>
{:else if !$clientSession}
<section class="dashboard-intro">
<div>
<p class="eyebrow">Client Workspace</p>
@@ -515,7 +529,7 @@
<tbody>
{#each focusCards as card}
<tr>
<td class="task-cell">
<td class="task-cell" data-label="Focus">
<div class="table-item">
<span class={`task-icon ${card.tone}`}>{card.code}</span>
<div>
@@ -524,19 +538,21 @@
</div>
</div>
</td>
<td>
<td data-label="Owner">
<div class="owner-chip">
<span>HP</span>
<strong>Hunter Premium Produce</strong>
</div>
</td>
<td>
<td data-label="Reference Date">
<div class="due-block">
<strong>{card.detail}</strong>
<span>Current checkpoint</span>
</div>
</td>
<td><span class={`status-chip ${card.tone}`}>{card.tone === 'warning' ? 'Watch' : 'On track'}</span></td>
<td data-label="Status">
<span class={`status-chip ${card.tone}`}>{card.tone === 'warning' ? 'Watch' : 'On track'}</span>
</td>
</tr>
{/each}
</tbody>
@@ -681,6 +697,10 @@
align-items: center;
}
.loading-banner {
min-height: 11rem;
}
.signin-form {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
@@ -759,8 +779,10 @@
.dashboard-grid {
display: grid;
grid-template-columns: minmax(0, 1.1fr) minmax(0, 1.15fr) 0.72fr;
grid-template-columns: minmax(0, 1.12fr) minmax(0, 1.02fr) minmax(16rem, 0.76fr);
grid-template-areas: 'market gauge metrics';
gap: 1rem;
align-items: stretch;
}
.analysis-grid {
@@ -775,6 +797,14 @@
gap: 1rem;
}
.market-card {
grid-area: market;
}
.gauge-card {
grid-area: gauge;
}
.card-toolbar {
align-items: flex-start;
margin-bottom: 1rem;
@@ -948,6 +978,7 @@
}
.metric-stack {
grid-area: metrics;
display: grid;
gap: 1rem;
}
@@ -1130,6 +1161,7 @@
table {
width: 100%;
min-width: 46rem;
border-collapse: separate;
border-spacing: 0 0.7rem;
}
@@ -1293,11 +1325,29 @@
}
@media (max-width: 1320px) {
.workspace-banner,
.dashboard-grid,
.analysis-grid,
.detail-grid,
.workspace-banner {
align-items: stretch;
}
.focus-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.dashboard-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
grid-template-areas:
'market gauge'
'metrics metrics';
}
.metric-stack {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
}
@media (max-width: 1120px) {
.analysis-grid,
.detail-grid {
grid-template-columns: 1fr;
}
@@ -1306,6 +1356,24 @@
}
}
@media (max-width: 900px) {
.dashboard-grid {
grid-template-columns: 1fr;
grid-template-areas:
'market'
'gauge'
'metrics';
}
.metric-stack {
grid-template-columns: 1fr;
}
.focus-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 860px) {
.dashboard-intro,
.intro-actions,
@@ -1320,7 +1388,6 @@
}
.preview-facts,
.metric-stack,
.signin-form {
grid-template-columns: 1fr;
}
@@ -1339,4 +1406,80 @@
row-gap: 0.5rem;
}
}
@media (max-width: 760px) {
.workspace-banner,
.panel-card,
.preview-body {
padding: 1rem;
}
table,
thead,
tbody,
tr,
td {
display: block;
width: 100%;
}
table {
min-width: 0;
border-spacing: 0;
}
thead {
display: none;
}
tbody {
display: grid;
gap: 0.9rem;
}
tbody tr {
padding: 0.3rem;
border: 1px solid var(--line);
border-radius: 1rem;
background: var(--panel-soft);
}
tbody td {
padding: 0.78rem 0.8rem;
white-space: normal;
border: none;
border-radius: 0;
background: transparent;
}
tbody td:first-child,
tbody td:last-child {
border: none;
border-radius: 0;
}
tbody td + td {
border-top: 1px solid var(--line);
}
tbody td::before {
content: attr(data-label);
display: block;
margin-bottom: 0.35rem;
color: var(--muted);
font-size: 0.72rem;
font-weight: 700;
letter-spacing: 0.06em;
text-transform: uppercase;
}
.task-cell {
min-width: 0;
}
.table-item,
.owner-chip {
align-items: flex-start;
}
}
</style>