Deployment fixes, add HPP logo
This commit is contained in:
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "data-entry-app-frontend",
|
||||
"version": "0.1.4",
|
||||
"version": "0.1.5",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "data-entry-app-frontend",
|
||||
"version": "0.1.4",
|
||||
"version": "0.1.5",
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "^3.2.0",
|
||||
"@sveltejs/adapter-node": "^5.2.12",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "data-entry-app-frontend",
|
||||
"version": "0.1.4",
|
||||
"version": "0.1.5",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
import { invalidateAll } from '$app/navigation';
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/state';
|
||||
import Lean101Logo from '$lib/components/Lean101Logo.svelte';
|
||||
import { clientSession, hasModuleAccess, sessionHydrated } from '$lib/session';
|
||||
import { featureFlags } from '$lib/features';
|
||||
import { onMount, tick } from 'svelte';
|
||||
import packageInfo from '../../../package.json';
|
||||
|
||||
@@ -24,7 +24,12 @@
|
||||
};
|
||||
|
||||
const dashboardItem: NavItem = { href: '/', label: 'Dashboard', shortLabel: 'DB', icon: 'home', moduleKey: 'dashboard' };
|
||||
const mixCalculatorItem: NavItem = { href: '/mix-calculator', label: 'Mix Calculator', shortLabel: 'MC', moduleKey: 'mix_calculator' };
|
||||
const mixCalculatorItem: NavItem = {
|
||||
href: featureFlags.mixCalculatorSessionHistory ? '/mix-calculator' : '/mix-calculator/new',
|
||||
label: 'Mix Calculator',
|
||||
shortLabel: 'MC',
|
||||
moduleKey: 'mix_calculator'
|
||||
};
|
||||
const workingDocumentItems: NavItem[] = [
|
||||
{ href: '/raw-materials', label: 'Raw Materials', shortLabel: 'RM', moduleKey: 'raw_materials' },
|
||||
{ href: '/mixes', label: 'Mix Master', shortLabel: 'MM', moduleKey: 'mix_master' },
|
||||
@@ -64,12 +69,16 @@
|
||||
description: 'Start a new costing worksheet for Hunter Premium Produce.',
|
||||
keywords: 'new mix create worksheet hunter premium produce formula'
|
||||
},
|
||||
{
|
||||
href: '/mix-calculator',
|
||||
label: 'Open Mix Calculator',
|
||||
description: 'Review saved production sessions and batch calculations.',
|
||||
keywords: 'mix calculator production sessions batch bags client product'
|
||||
},
|
||||
...(featureFlags.mixCalculatorSessionHistory
|
||||
? [
|
||||
{
|
||||
href: '/mix-calculator',
|
||||
label: 'Open Mix Calculator',
|
||||
description: 'Review saved production sessions and batch calculations.',
|
||||
keywords: 'mix calculator production sessions batch bags client product'
|
||||
}
|
||||
]
|
||||
: []),
|
||||
{
|
||||
href: '/mix-calculator/new',
|
||||
label: 'Create Mix Calculation',
|
||||
@@ -281,7 +290,9 @@
|
||||
Promise.all([
|
||||
hasModuleAccess(session, 'products') ? api.products() : Promise.resolve([]),
|
||||
hasModuleAccess(session, 'mix_master') ? api.mixes() : Promise.resolve([]),
|
||||
hasModuleAccess(session, 'mix_calculator') ? api.mixCalculatorSessions() : Promise.resolve([])
|
||||
featureFlags.mixCalculatorSessionHistory && hasModuleAccess(session, 'mix_calculator')
|
||||
? api.mixCalculatorSessions()
|
||||
: Promise.resolve([])
|
||||
])
|
||||
.then(([products, mixes, sessions]) => {
|
||||
if (seededSearchToken !== token) {
|
||||
@@ -382,7 +393,7 @@
|
||||
<aside class="sidebar">
|
||||
<div class="brand-row">
|
||||
<a class="brand" href="/">
|
||||
<Lean101Logo className="sidebar-logo" showTagline={false} />
|
||||
<img class="sidebar-logo" src="/logo-hsf.png" alt="Hunter Premium Produce" />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -421,7 +432,9 @@
|
||||
|
||||
{#if visibleMixCalculatorItem}
|
||||
<a class:active={matchesRoute(visibleMixCalculatorItem.href, page.url.pathname)} href={visibleMixCalculatorItem.href}>
|
||||
<span class="nav-icon">{visibleMixCalculatorItem.shortLabel}</span>
|
||||
<span class="nav-icon">
|
||||
<span class="nav-icon-mask" style="--nav-icon-url: url('/icons/calculator.svg');" aria-hidden="true"></span>
|
||||
</span>
|
||||
<span>{visibleMixCalculatorItem.label}</span>
|
||||
</a>
|
||||
{/if}
|
||||
@@ -560,7 +573,7 @@
|
||||
<div class="menu-panel quick-fab-panel">
|
||||
<a href="/mixes">Open mix costing</a>
|
||||
<a href="/mixes/new">Create mix worksheet</a>
|
||||
<a href="/mix-calculator">Open mix calculator</a>
|
||||
<a href={featureFlags.mixCalculatorSessionHistory ? '/mix-calculator' : '/mix-calculator/new'}>Open mix calculator</a>
|
||||
<a href="/mix-calculator/new">Create mix session</a>
|
||||
<a href="/products">Review delivered pricing</a>
|
||||
<button type="button" onclick={() => openPalette('')}>Search the workspace</button>
|
||||
@@ -687,7 +700,9 @@
|
||||
|
||||
{#if visibleMixCalculatorItem}
|
||||
<a class:active={matchesRoute(visibleMixCalculatorItem.href, page.url.pathname)} href={visibleMixCalculatorItem.href} onclick={() => (navOpen = false)}>
|
||||
<span class="nav-icon">{visibleMixCalculatorItem.shortLabel}</span>
|
||||
<span class="nav-icon">
|
||||
<span class="nav-icon-mask" style="--nav-icon-url: url('/icons/calculator.svg');" aria-hidden="true"></span>
|
||||
</span>
|
||||
<span>{visibleMixCalculatorItem.label}</span>
|
||||
</a>
|
||||
{/if}
|
||||
@@ -918,16 +933,19 @@
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.sidebar :global(.sidebar-logo) {
|
||||
width: min(100%, 12.2rem);
|
||||
.nav-icon-mask {
|
||||
display: inline-block;
|
||||
width: 60%;
|
||||
height: 60%;
|
||||
background-color: currentColor;
|
||||
-webkit-mask: var(--nav-icon-url) center / contain no-repeat;
|
||||
mask: var(--nav-icon-url) center / contain no-repeat;
|
||||
}
|
||||
|
||||
.sidebar :global(.sidebar-logo .logo-copy strong) {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
.sidebar :global(.sidebar-logo .logo-mark) {
|
||||
width: 2.6rem;
|
||||
.sidebar .sidebar-logo {
|
||||
width: min(100%, 13.5rem);
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.nav-toggle,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { api } from '$lib/api';
|
||||
import { featureFlags } from '$lib/features';
|
||||
import { clientSession, hasModuleAccess } from '$lib/session';
|
||||
import type {
|
||||
MixCalculatorCreateInput,
|
||||
@@ -169,7 +170,25 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function saveSession(mode: 'update' | 'create') {
|
||||
function clearForm() {
|
||||
clientName = options.clients[0] ?? '';
|
||||
productId = 0;
|
||||
mixDate = todayIso;
|
||||
batchSizeKg = '';
|
||||
preparedByName = $clientSession?.name ?? '';
|
||||
notes = '';
|
||||
preview = null;
|
||||
formError = '';
|
||||
formSuccess = '';
|
||||
}
|
||||
|
||||
function printPreview() {
|
||||
if (typeof window !== 'undefined') {
|
||||
window.print();
|
||||
}
|
||||
}
|
||||
|
||||
async function saveSession(mode: 'update' | 'create', destination: 'detail' | 'print' = 'detail') {
|
||||
const payload = buildPayload();
|
||||
if (!payload) {
|
||||
return;
|
||||
@@ -182,7 +201,8 @@
|
||||
? await api.updateMixCalculatorSession(initialSession.id, payload)
|
||||
: await api.createMixCalculatorSession(payload);
|
||||
|
||||
await goto(`/mix-calculator/${saved.id}`);
|
||||
const target = destination === 'print' ? `/mix-calculator/${saved.id}/print` : `/mix-calculator/${saved.id}`;
|
||||
await goto(target);
|
||||
} catch (error) {
|
||||
formError = error instanceof Error ? error.message : 'Unable to save the mix calculator session.';
|
||||
saveLoading = false;
|
||||
@@ -195,17 +215,24 @@
|
||||
<p class="eyebrow">Mix Calculator</p>
|
||||
<h2>Edit access is required to create a new session.</h2>
|
||||
<p>View-only users can open saved sessions from history, but cannot create or update production calculations.</p>
|
||||
<a class="secondary-button" href="/mix-calculator">Back to session history</a>
|
||||
{#if featureFlags.mixCalculatorSessionHistory}
|
||||
<a class="secondary-button" href="/mix-calculator">Back to session history</a>
|
||||
{/if}
|
||||
</section>
|
||||
{:else}
|
||||
<section class="page-intro">
|
||||
<div>
|
||||
<p class="eyebrow">Mix Calculator</p>
|
||||
<p class="eyebrow">
|
||||
<span class="eyebrow-icon" style="--button-icon-url: url('/icons/calculator.svg');" aria-hidden="true"></span>
|
||||
<span>Mix Calculator</span>
|
||||
</p>
|
||||
<h2>{isExistingSession ? 'Edit saved mix session' : 'New mix calculation session'}</h2>
|
||||
<p>Scale a saved product mix by batch size, review required raw materials, then save the session for history and printing.</p>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<a class="secondary-button" href="/mix-calculator">Session history</a>
|
||||
{#if featureFlags.mixCalculatorSessionHistory}
|
||||
<a class="secondary-button" href="/mix-calculator">Session history</a>
|
||||
{/if}
|
||||
{#if initialSession}
|
||||
<a class="secondary-button" href={`/mix-calculator/${initialSession.id}/print`}>Printable view</a>
|
||||
{/if}
|
||||
@@ -288,18 +315,36 @@
|
||||
{#if canEdit}
|
||||
<div class="action-row">
|
||||
<button class="primary-button" disabled={previewLoading || saveLoading} type="button" onclick={calculatePreview}>
|
||||
{previewLoading ? 'Calculating...' : 'Calculate mix'}
|
||||
<span class="button-icon" style="--button-icon-url: url('/icons/calculator.svg');" aria-hidden="true"></span>
|
||||
<span>{previewLoading ? 'Calculating...' : 'Calculate mix'}</span>
|
||||
</button>
|
||||
|
||||
<button class="secondary-button" disabled={saveLoading || previewLoading} type="button" onclick={() => saveSession(isExistingSession ? 'update' : 'create')}>
|
||||
{saveLoading ? 'Saving...' : isExistingSession ? 'Save changes' : 'Save session'}
|
||||
</button>
|
||||
{#if featureFlags.mixCalculatorSessionSave}
|
||||
<button class="secondary-button" disabled={saveLoading || previewLoading} type="button" onclick={() => saveSession(isExistingSession ? 'update' : 'create')}>
|
||||
{saveLoading ? 'Saving...' : isExistingSession ? 'Save changes' : 'Save session'}
|
||||
</button>
|
||||
|
||||
{#if initialSession}
|
||||
<button class="secondary-button" disabled={saveLoading || previewLoading} type="button" onclick={() => saveSession('create')}>
|
||||
Save as new
|
||||
<button class="secondary-button" disabled={saveLoading || previewLoading} type="button" onclick={() => saveSession(isExistingSession ? 'update' : 'create', 'print')}>
|
||||
<span class="button-icon" style="--button-icon-url: url('/icons/print.svg');" aria-hidden="true"></span>
|
||||
<span>{saveLoading ? 'Saving...' : 'Save & print'}</span>
|
||||
</button>
|
||||
|
||||
{#if initialSession}
|
||||
<button class="secondary-button" disabled={saveLoading || previewLoading} type="button" onclick={() => saveSession('create')}>
|
||||
Save as new
|
||||
</button>
|
||||
{/if}
|
||||
{:else}
|
||||
<button class="secondary-button" disabled={previewLoading || saveLoading || !preview} type="button" onclick={printPreview}>
|
||||
<span class="button-icon" style="--button-icon-url: url('/icons/print.svg');" aria-hidden="true"></span>
|
||||
<span>Print</span>
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
<button class="secondary-button" disabled={previewLoading || saveLoading} type="button" onclick={clearForm}>
|
||||
<span class="button-icon" style="--button-icon-url: url('/icons/trash.svg');" aria-hidden="true"></span>
|
||||
<span>Clear</span>
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
</article>
|
||||
@@ -396,6 +441,92 @@
|
||||
{/if}
|
||||
</article>
|
||||
</section>
|
||||
|
||||
{#if preview}
|
||||
<section class="print-only" aria-hidden="true">
|
||||
<article class="print-sheet">
|
||||
<header class="print-header">
|
||||
<div>
|
||||
<p class="print-eyebrow">Mix Calculator</p>
|
||||
<h1>{preview.product_name}</h1>
|
||||
<p class="print-subtitle">{preview.client_name} · {preview.mix_name}</p>
|
||||
</div>
|
||||
<div class="print-meta">
|
||||
<div>
|
||||
<span>Mix date</span>
|
||||
<strong>{formatDate(preview.mix_date)}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>Prepared by</span>
|
||||
<strong>{preview.prepared_by_name}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section class="print-summary">
|
||||
<div>
|
||||
<span>Batch size</span>
|
||||
<strong>{formatNumber(preview.batch_size_kg, 2)}kg</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>Total kilograms</span>
|
||||
<strong>{formatNumber(preview.total_kg, 2)}kg</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>Total bags</span>
|
||||
<strong>{formatNumber(preview.total_bags, 2)}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>Unit size</span>
|
||||
<strong>{formatNumber(preview.product_unit_size_kg, 2)}kg</strong>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{#if preview.notes}
|
||||
<section class="print-notes">
|
||||
<h2>Notes</h2>
|
||||
<p>{preview.notes}</p>
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
{#if preview.warnings.length}
|
||||
<section class="print-warnings">
|
||||
<h2>Warnings</h2>
|
||||
{#each preview.warnings as warning}
|
||||
<p>{warning}</p>
|
||||
{/each}
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
<section class="print-table">
|
||||
<div class="print-table-header">
|
||||
<h2>Required raw materials</h2>
|
||||
<span>{preview.product_unit_of_measure} · {formatNumber(preview.product_unit_size_kg, 2)}kg per unit</span>
|
||||
</div>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Raw material</th>
|
||||
<th>Mix %</th>
|
||||
<th>Required kg</th>
|
||||
<th>Unit</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each preview.lines as line}
|
||||
<tr>
|
||||
<td>{line.raw_material_name}</td>
|
||||
<td>{formatNumber(line.mix_percentage, 2)}%</td>
|
||||
<td>{formatNumber(line.required_kg, 2)}kg</td>
|
||||
<td>{line.unit}</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
</article>
|
||||
</section>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
@@ -411,6 +542,18 @@
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.45rem;
|
||||
}
|
||||
|
||||
.eyebrow-icon {
|
||||
display: inline-block;
|
||||
width: 0.95rem;
|
||||
height: 0.95rem;
|
||||
background-color: currentColor;
|
||||
-webkit-mask: var(--button-icon-url) center / contain no-repeat;
|
||||
mask: var(--button-icon-url) center / contain no-repeat;
|
||||
}
|
||||
|
||||
.page-intro,
|
||||
@@ -593,6 +736,7 @@
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.78rem 0.96rem;
|
||||
border-radius: 0.9rem;
|
||||
border: 1px solid var(--line-strong);
|
||||
@@ -632,6 +776,16 @@
|
||||
box-shadow: 0 10px 22px rgba(24, 38, 29, 0.08);
|
||||
}
|
||||
|
||||
.button-icon {
|
||||
display: inline-block;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
background-color: currentColor;
|
||||
-webkit-mask: var(--button-icon-url) center / contain no-repeat;
|
||||
mask: var(--button-icon-url) center / contain no-repeat;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
cursor: wait;
|
||||
opacity: 0.7;
|
||||
@@ -781,4 +935,151 @@
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
|
||||
.print-only {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media print {
|
||||
:global(body) {
|
||||
background: #fff !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
:global(body *) {
|
||||
visibility: hidden !important;
|
||||
}
|
||||
|
||||
.print-only,
|
||||
.print-only :global(*) {
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
.print-only {
|
||||
display: block;
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
padding: 1.4cm;
|
||||
background: #fff;
|
||||
color: #1a2421;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.print-sheet {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.print-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 1.5rem;
|
||||
padding-bottom: 1rem;
|
||||
border-bottom: 1px solid #cbd6cf;
|
||||
}
|
||||
|
||||
.print-header h1 {
|
||||
margin: 0.25rem 0 0.3rem;
|
||||
font-size: 1.7rem;
|
||||
}
|
||||
|
||||
.print-eyebrow {
|
||||
color: #5f6f67;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.print-subtitle {
|
||||
color: #5f6f67;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.print-meta {
|
||||
display: grid;
|
||||
gap: 0.55rem;
|
||||
min-width: 12rem;
|
||||
}
|
||||
|
||||
.print-meta div,
|
||||
.print-summary div {
|
||||
display: grid;
|
||||
gap: 0.1rem;
|
||||
}
|
||||
|
||||
.print-meta span,
|
||||
.print-summary span,
|
||||
.print-table-header span {
|
||||
color: #5f6f67;
|
||||
font-size: 0.72rem;
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.print-summary {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 0.85rem;
|
||||
padding: 1rem 0;
|
||||
border-bottom: 1px solid #cbd6cf;
|
||||
}
|
||||
|
||||
.print-notes,
|
||||
.print-warnings {
|
||||
margin-top: 0.85rem;
|
||||
padding: 0.75rem 0.9rem;
|
||||
border: 1px solid #cbd6cf;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.print-warnings {
|
||||
border-color: #d8a76b;
|
||||
background: #fff6e6;
|
||||
color: #8b5b1e;
|
||||
}
|
||||
|
||||
.print-notes h2,
|
||||
.print-warnings h2,
|
||||
.print-table-header h2 {
|
||||
margin: 0 0 0.35rem;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.print-table {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.print-table-header {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.print-table table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
.print-table th,
|
||||
.print-table td {
|
||||
padding: 0.55rem 0.5rem;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #cbd6cf;
|
||||
font-size: 0.92rem;
|
||||
}
|
||||
|
||||
.print-table th {
|
||||
color: #5f6f67;
|
||||
font-size: 0.72rem;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
@page {
|
||||
margin: 1cm;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { env } from '$env/dynamic/public';
|
||||
|
||||
function flagEnabled(value: string | undefined, defaultValue: boolean): boolean {
|
||||
if (value === undefined || value === null || value.trim() === '') {
|
||||
return defaultValue;
|
||||
}
|
||||
return ['1', 'true', 'yes', 'on'].includes(value.trim().toLowerCase());
|
||||
}
|
||||
|
||||
export const featureFlags = {
|
||||
mixCalculatorSessionHistory: flagEnabled(env.PUBLIC_MIX_CALCULATOR_SESSION_HISTORY, false),
|
||||
mixCalculatorSessionSave: flagEnabled(env.PUBLIC_MIX_CALCULATOR_SESSION_SAVE, false)
|
||||
};
|
||||
@@ -303,7 +303,7 @@
|
||||
<div class="auth-card auth-card-loading">
|
||||
<div class="auth-header">
|
||||
<div class="client-logo-block">
|
||||
<img class="hero-login-logo" src="/lean101-login-logo.png" alt="Lean 101" />
|
||||
<img class="hero-login-logo" src="/logo-hsf.png" alt="Lean 101" />
|
||||
<div class="client-logo-copy">
|
||||
<p class="eyebrow">Client Workspace</p>
|
||||
<strong>Hunter Premium Produce</strong>
|
||||
@@ -327,7 +327,7 @@
|
||||
|
||||
<div class="auth-footer">
|
||||
<div class="lean-brand">
|
||||
<img class="footer-login-logo" src="/lean101-login-logo.png" alt="Lean 101" />
|
||||
<img class="footer-login-logo" src="/logo-hsf.png" alt="Lean 101" />
|
||||
</div>
|
||||
<div class="auth-meta">
|
||||
<span class="version-badge">
|
||||
@@ -344,7 +344,7 @@
|
||||
<div class="auth-card auth-card-login">
|
||||
<div class="auth-header">
|
||||
<div class="client-logo-block">
|
||||
<img class="hero-login-logo" src="/lean101-login-logo.png" alt="Lean 101" />
|
||||
<img class="hero-login-logo" src="/logo-hsf.png" alt="Lean 101" />
|
||||
<div class="client-logo-copy">
|
||||
<p class="eyebrow">Client Sign-In</p>
|
||||
<strong>Hunter Premium Produce</strong>
|
||||
@@ -389,7 +389,7 @@
|
||||
|
||||
<div class="auth-footer">
|
||||
<div class="lean-brand">
|
||||
<img class="footer-login-logo" src="/lean101-login-logo.png" alt="Lean 101" />
|
||||
<img class="footer-login-logo" src="/logo-hsf.png" alt="Lean 101" />
|
||||
</div>
|
||||
<div class="auth-meta">
|
||||
<span class="version-badge">
|
||||
@@ -798,13 +798,13 @@
|
||||
}
|
||||
|
||||
.hero-login-logo {
|
||||
width: min(100%, 19rem);
|
||||
width: min(100%, 24rem);
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.footer-login-logo {
|
||||
width: 9.8rem;
|
||||
width: 12rem;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import { api } from '$lib/api';
|
||||
import { featureFlags } from '$lib/features';
|
||||
import { getStoredClientSession, hasModuleAccess, hasStoredClientSession } from '$lib/session';
|
||||
|
||||
export async function load({ fetch }) {
|
||||
if (!featureFlags.mixCalculatorSessionHistory) {
|
||||
throw redirect(307, '/mix-calculator/new');
|
||||
}
|
||||
|
||||
if (!hasStoredClientSession()) {
|
||||
return {
|
||||
sessions: []
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import MixCalculatorWorkspace from '$lib/components/MixCalculatorWorkspace.svelte';
|
||||
import { featureFlags } from '$lib/features';
|
||||
|
||||
let { data } = $props();
|
||||
</script>
|
||||
@@ -11,7 +12,11 @@
|
||||
<p class="eyebrow">Mix Calculator</p>
|
||||
<h2>Session unavailable.</h2>
|
||||
<p>The requested mix calculator session could not be loaded with the current access scope.</p>
|
||||
<a class="secondary-button" href="/mix-calculator">Back to session history</a>
|
||||
{#if featureFlags.mixCalculatorSessionHistory}
|
||||
<a class="secondary-button" href="/mix-calculator">Back to session history</a>
|
||||
{:else}
|
||||
<a class="secondary-button" href="/mix-calculator/new">New mix session</a>
|
||||
{/if}
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import MixCalculatorPrintSheet from '$lib/components/MixCalculatorPrintSheet.svelte';
|
||||
import { featureFlags } from '$lib/features';
|
||||
|
||||
let { data } = $props();
|
||||
</script>
|
||||
@@ -11,7 +12,11 @@
|
||||
<p class="eyebrow">Mix Calculator</p>
|
||||
<h2>Printable session unavailable.</h2>
|
||||
<p>The saved session could not be loaded for printing.</p>
|
||||
<a class="secondary-button" href="/mix-calculator">Back to session history</a>
|
||||
{#if featureFlags.mixCalculatorSessionHistory}
|
||||
<a class="secondary-button" href="/mix-calculator">Back to session history</a>
|
||||
{:else}
|
||||
<a class="secondary-button" href="/mix-calculator/new">New mix session</a>
|
||||
{/if}
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--! Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. --><path d="M0 64C0 28.7 28.7 0 64 0L320 0c35.3 0 64 28.7 64 64l0 384c0 35.3-28.7 64-64 64L64 512c-35.3 0-64-28.7-64-64L0 64zM96 80l0 64c0 8.8 7.2 16 16 16l160 0c8.8 0 16-7.2 16-16l0-64c0-8.8-7.2-16-16-16L112 64c-8.8 0-16 7.2-16 16zm32 128a32 32 0 1 0 -64 0 32 32 0 1 0 64 0zm64 32a32 32 0 1 0 0-64 32 32 0 1 0 0 64zm96-32a32 32 0 1 0 -64 0 32 32 0 1 0 64 0zM64 304a32 32 0 1 0 64 0 32 32 0 1 0 -64 0zm32 128a32 32 0 1 0 0-64 32 32 0 1 0 0 64zm64-128a32 32 0 1 0 64 0 32 32 0 1 0 -64 0zm32 128a32 32 0 1 0 0-64 32 32 0 1 0 0 64zm64-96l0 96c0 17.7 14.3 32 32 32s32-14.3 32-32l0-96c0-17.7-14.3-32-32-32s-32 14.3-32 32z"/></svg>
|
||||
|
After Width: | Height: | Size: 895 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. --><path d="M128 0C92.7 0 64 28.7 64 64l0 96 64 0 0-96 226.7 0L384 93.3l0 66.7 64 0 0-66.7c0-17-6.7-33.3-18.7-45.3L400 18.7C388 6.7 371.7 0 354.7 0L128 0zM384 352l0 32 0 64-256 0 0-64 0-16 0-16 256 0zm64 32l32 0c17.7 0 32-14.3 32-32l0-96c0-35.3-28.7-64-64-64L64 192c-35.3 0-64 28.7-64 64l0 96c0 17.7 14.3 32 32 32l32 0 0 64c0 35.3 28.7 64 64 64l256 0c35.3 0 64-28.7 64-64l0-64zM432 248a24 24 0 1 1 0 48 24 24 0 1 1 0-48z"/></svg>
|
||||
|
After Width: | Height: | Size: 699 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. --><path d="M135.2 17.7L128 32 32 32C14.3 32 0 46.3 0 64S14.3 96 32 96l384 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l-96 0-7.2-14.3C307.4 6.8 296.3 0 284.2 0L163.8 0c-12.1 0-23.2 6.8-28.6 17.7zM416 128L32 128 53.2 467c1.6 25.3 22.6 45 47.9 45l245.8 0c25.3 0 46.3-19.7 47.9-45L416 128z"/></svg>
|
||||
|
After Width: | Height: | Size: 559 B |
Binary file not shown.
|
After Width: | Height: | Size: 693 KiB |
Reference in New Issue
Block a user