Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -1063,6 +1063,103 @@ label,
border-color: color-mix(in srgb, var(--info) 28%, transparent);
}


.operator-priority-card {
padding: clamp(1rem, 2vw, 1.35rem);
border: 1px solid color-mix(in srgb, var(--accent) 36%, var(--border));
border-radius: var(--radius-xl);
background: linear-gradient(180deg, color-mix(in srgb, var(--accent-soft) 58%, var(--surface)), var(--surface));
box-shadow: var(--shadow-md);
}

.operator-priority-card .eyebrow {
color: var(--accent-strong);
}

.support-section {
opacity: 0.88;
}

.support-section .panel,
.support-section.panel,
.support-section .subpanel,
.support-section.page-context-card {
box-shadow: none;
}

.support-section .stat-card strong {
font-size: clamp(1.25rem, 2vw, 1.6rem);
}

.shell-nav-admin {
opacity: 0.78;
}

.shell-nav-admin .shell-nav-section-label::after {
content: ' / setup';
font-weight: 600;
letter-spacing: 0.04em;
text-transform: none;
}

.shell-nav-link.is-admin-link {
color: var(--muted);
background: transparent;
border-color: transparent;
}

.shell-nav-link.is-admin-link.is-active {
color: var(--ink-soft);
background: var(--surface-soft);
border-color: var(--border);
box-shadow: none;
}

.badge,
.summary-pill {
cursor: default;
}

a.summary-pill,
button.summary-pill,
.panel-link,
.inline-link,
.button-primary,
.button-secondary,
.button-ghost,
.shell-nav-link {
cursor: pointer;
}

a.summary-pill {
transition:
border-color 140ms ease,
background-color 140ms ease,
box-shadow 140ms ease;
}

a.summary-pill:hover,
a.summary-pill:focus-visible {
border-color: var(--border-strong);
background: var(--surface);
box-shadow: var(--shadow-sm);
}

.order-card:hover,
.line-entry-card:hover,
.timeline-card:hover {
border-color: var(--border);
}

.order-card:has(a:hover),
.order-card:has(a:focus-visible),
.line-entry-card:has(button:hover),
.line-entry-card:has(button:focus-visible),
.timeline-card:has(a:hover),
.timeline-card:has(a:focus-visible) {
border-color: var(--border-strong);
}

.button-primary {
background: linear-gradient(180deg, var(--accent), var(--accent-strong));
color: white;
Expand Down
22 changes: 19 additions & 3 deletions app/handoff/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,23 @@ export default async function HandoffPage({
{params?.saved ? <p className="inline-success"><CheckIcon className="button-icon" />{t('handoff.savedUpdate', { item: params.saved })}</p> : null}
{params?.error ? <p className="inline-warning">{params.error}</p> : null}

<section className="grid-two">
<section className="operator-priority-card page-stack">
<div className="table-header-row">
<div>
<p className="eyebrow">Primary action</p>
<h2>Release ready work and record handoff notes</h2>
<p className="helper-text">Check pickup, packing, and assignment watches first. Use WIP and shift notes when work must cross a shift.</p>
</div>
<HandoffIcon className="callout-icon" />
</div>
<div className="inline-action-row action-row-start">
<a href="#handoff-watch" className="button-primary compact-button"><HandoffIcon className="button-icon" />Review release watches</a>
<a href="#handoff-forms" className="button-secondary compact-button"><CheckIcon className="button-icon" />Record WIP / shift note</a>
<Link href="/production" className="button-ghost compact-button"><ProductionIcon className="button-icon" />Production board</Link>
</div>
</section>

<section className="grid-two support-section">
<article className="panel page-stack">
<div className="table-header-row">
<div>
Expand Down Expand Up @@ -123,7 +139,7 @@ export default async function HandoffPage({
</article>
</section>

<section className="grid-two">
<section className="grid-two" id="handoff-watch">
<article className="panel page-stack">
<div className="table-header-row">
<div>
Expand Down Expand Up @@ -232,7 +248,7 @@ export default async function HandoffPage({
</article>
</section>

<section className="grid-two">
<section className="grid-two" id="handoff-forms">
<form action={addWipEntryAction} className="panel form-grid compact-form page-stack">
<div>
<p className="eyebrow">{t('handoff.addWip')}</p>
Expand Down
18 changes: 17 additions & 1 deletion app/orders/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,23 @@ export default async function OrdersPage({
</p>
) : null}

<section className="panel page-stack">
<section className="operator-priority-card page-stack">
<div className="table-header-row">
<div>
<p className="eyebrow">Primary action</p>
<h2>Create or review today&apos;s orders</h2>
<p className="helper-text">Order capture is the first-deploy priority. Confirm products when useful, but freeform lines can keep work moving.</p>
</div>
<OrdersIcon className="callout-icon" />
</div>
<div className="inline-action-row action-row-start">
<Link href="/orders/new" className="button-primary compact-button"><OrdersIcon className="button-icon" />Create order</Link>
<Link href="/customers" className="button-secondary compact-button">Confirm customers</Link>
<Link href="/admin/setup?section=products#products" className="button-ghost compact-button">Confirm products</Link>
</div>
</section>

<section className="panel page-stack support-section">
<div className="table-header-row">
<div>
<strong>{t('orders.recurringDemand')}</strong>
Expand Down
29 changes: 16 additions & 13 deletions app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,27 +149,28 @@ export default async function HomePage() {
</div>
</section>

<section className="panel page-stack">
<section className="operator-priority-card page-stack">
<div className="table-header-row">
<div>
<h2>First deploy workflow</h2>
<p className="helper-text">For a real first test, start with customers and order capture, then use production and handoff as the daily operating loop.</p>
<p className="eyebrow">Today&apos;s priority</p>
<h2>Start the daily loop</h2>
<p className="helper-text">Create or confirm orders first. Production and handoff become useful once real orders exist.</p>
</div>
<span className="summary-pill">MWP path</span>
</div>
<div className="inline-action-row">
<Link href={skossinaRoutes.customers} className="button-secondary compact-button">Confirm customers</Link>
<Link href={skossinaRoutes.orders} className="button-primary compact-button">Create orders</Link>
<Link href={skossinaRoutes.production} className="button-secondary compact-button">Track production</Link>
<Link href={skossinaRoutes.handoff} className="button-secondary compact-button">Record handoff</Link>
<Link href={skossCoreRoutes.adminSetup} className="button-secondary compact-button">Basic setup</Link>
<div className="inline-action-row action-row-start">
<Link href={skossinaRoutes.orders} className="button-primary compact-button"><OrdersIcon className="button-icon" />Create order</Link>
<Link href={skossinaRoutes.production} className="button-secondary compact-button"><ProductionIcon className="button-icon" />Track production</Link>
<Link href={skossinaRoutes.handoff} className="button-secondary compact-button"><HandoffIcon className="button-icon" />Record handoff</Link>
<Link href={skossinaRoutes.customers} className="button-ghost compact-button"><CustomersIcon className="button-icon" />Customers</Link>
<Link href={skossCoreRoutes.adminSetup} className="button-ghost compact-button"><SetupIcon className="button-icon" />Basic setup</Link>
</div>
{gatewayState.demoModeActive ? (
<p className="inline-warning">This workspace is marked as demo data. Do not treat records here as live operational data.</p>
) : null}
</section>

<section className="grid-two">
<section className="grid-two support-section">
<article className="panel page-stack">
<div className="table-header-row">
<div>
Expand Down Expand Up @@ -207,14 +208,16 @@ export default async function HomePage() {
</article>
</section>

<ActivityFeed
<div className="support-section">
<ActivityFeed
title={t('activity.homeTitle')}
description={t('activity.homeHelp')}
emptyLabel={t('activity.empty')}
items={summary.recentActivities}
/>
</div>

<section className="page-context-card">
<section className="page-context-card support-section">
<SparklesIcon className="callout-icon" />
<div>
<strong>{t('home.roleFocusTitle')}</strong>
Expand All @@ -229,7 +232,7 @@ export default async function HomePage() {
</div>
</section>

<section className="grid-cards">
<section className="grid-cards support-section">
{orderedQuickLinks.map((link, index) => {
const Icon = link.icon;
const isRecommended = homeWorkspace === 'home' ? index === 0 : link.href === `/${recommendedWorkspace}`;
Expand Down
32 changes: 25 additions & 7 deletions app/production/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,24 @@ export default async function ProductionPage() {
</div>
</section>

{view.boards.map((board) => {
<section className="operator-priority-card page-stack">
<div className="table-header-row">
<div>
<p className="eyebrow">Primary action</p>
<h2>Update pending production work</h2>
<p className="helper-text">Use the line update cards on each board to mark what is done. Create orders only when demand is missing.</p>
</div>
<ProductionIcon className="callout-icon" />
</div>
<div className="inline-action-row action-row-start">
<a href="#production-work" className="button-primary compact-button"><CheckIcon className="button-icon" />Update production</a>
<Link href="/orders/new" className="button-secondary compact-button"><OrdersIcon className="button-icon" />Create order</Link>
<Link href="/handoff" className="button-ghost compact-button"><HandoffIcon className="button-icon" />Record WIP / handoff</Link>
</div>
</section>

<div id="production-work" className="page-stack">
{view.boards.map((board) => {
const sectionIdBase = board.productionDate;

return (
Expand Down Expand Up @@ -130,7 +147,7 @@ export default async function ProductionPage() {
) : null}

<div
className="stats-grid compact-stats-grid"
className="stats-grid compact-stats-grid support-section"
id={`${sectionIdBase}-demand`}
>
<div className="stat-card">
Expand Down Expand Up @@ -163,7 +180,7 @@ export default async function ProductionPage() {
</div>
</div>

<div className="stats-grid compact-stats-grid">
<div className="stats-grid compact-stats-grid support-section">
<div className="stat-card">
<span className="stat-label">
{t('production.fulfillmentSummary.standard')}
Expand Down Expand Up @@ -240,7 +257,7 @@ export default async function ProductionPage() {
))}
</div>

<div className="grid-two" id={`${sectionIdBase}-fulfillment`}>
<div className="grid-two support-section" id={`${sectionIdBase}-fulfillment`}>
<article className="subpanel page-stack">
<div className="table-header-row">
<div>
Expand Down Expand Up @@ -307,7 +324,7 @@ export default async function ProductionPage() {
</article>
</div>

<div className="grid-two">
<div className="grid-two support-section">
<article className="subpanel page-stack">
<div className="table-header-row">
<div>
Expand Down Expand Up @@ -361,7 +378,7 @@ export default async function ProductionPage() {
</article>
</div>

<div className="grid-two" id={`${sectionIdBase}-handoff`}>
<div className="grid-two support-section" id={`${sectionIdBase}-handoff`}>
<article className="subpanel page-stack">
<div className="table-header-row">
<div>
Expand Down Expand Up @@ -565,7 +582,8 @@ export default async function ProductionPage() {
</article>
</section>
);
})}
})}
</div>

{!view.boards.length ? (
<section className="page-context-card">
Expand Down
22 changes: 15 additions & 7 deletions app/timeline/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -175,15 +175,23 @@ export default async function TimelinePage() {
</Link>
</section>

<section className="page-context-card">
<TimelineIcon className="callout-icon" />
<div>
<strong>{t('timeline.focusDateTitle', { date: formatDateLabel(view.focusDate, locale) })}</strong>
<p className="helper-text no-margin">{t('timeline.focusDateBody')}</p>
<section className="operator-priority-card page-stack">
<div className="table-header-row">
<div>
<p className="eyebrow">Support view</p>
<h2>{t('timeline.focusDateTitle', { date: formatDateLabel(view.focusDate, locale) })}</h2>
<p className="helper-text">Use timeline to spot timing risk. Daily work still happens in orders, production, and handoff.</p>
</div>
<TimelineIcon className="callout-icon" />
</div>
<div className="inline-action-row action-row-start">
<Link href="/orders" className="button-primary compact-button"><OrdersIcon className="button-icon" />Open orders</Link>
<Link href="/production" className="button-secondary compact-button">Production board</Link>
<Link href="/handoff" className="button-ghost compact-button">Handoff</Link>
</div>
</section>

<section className="stats-grid compact-stats-grid">
<section className="stats-grid compact-stats-grid support-section">
<div className="stat-card stat-card-warn">
<span className="stat-label">{t('timeline.summary.overdue')}</span>
<strong>{view.summary.overdue}</strong>
Expand Down Expand Up @@ -234,7 +242,7 @@ export default async function TimelinePage() {
</div>
</article>

<div className="page-stack">
<div className="page-stack support-section">
<article className="panel page-stack">
<div className="table-header-row">
<div>
Expand Down
2 changes: 1 addition & 1 deletion components/primary-nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function NavLink({
return (
<Link
href={href}
className={`shell-nav-link ${compact ? 'is-compact' : ''} ${active ? 'is-active' : ''}`}
className={`shell-nav-link ${compact ? 'is-compact is-admin-link' : ''} ${active ? 'is-active' : ''}`}
aria-current={active ? 'page' : undefined}
>
{children}
Expand Down
6 changes: 6 additions & 0 deletions docs/mwp-readiness-audit.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ Do not include these in the first deploy readiness scope:
- Added production entry links and clearer empty guidance for production boards with no visible orders.
- Added handoff entry links and empty-list guidance for WIP, packing, assignment, pickup, and focus-day order watches.

## Product/menu benchmark note

The current product setup path is intentionally MWP-only. It is meant to confirm basic sellable product names, default units, optional category labels, and active/inactive state so real orders can be captured. It should not be judged as a full POS/menu manager yet.

Loyverse, Uber Eats, and DiDi Food are useful later benchmarks for product/menu UX patterns such as richer descriptions, prices, images, modifiers, variants, availability, menu grouping, and channel-specific presentation. Those remain post-MWP/beta work for SKOSS. The first deploy should preserve the current principle: product setup helps order capture, but incomplete catalog data must not block daily kitchen work.

## Recommended next PR

Run a first-deploy rehearsal against a fresh non-demo instance: bootstrap, create admin, confirm products/customers, create orders, update production, record WIP, record handoff, and verify browser-print output. Keep the rehearsal focused on operational confidence before adding richer catalog, procurement, inventory, or deployment automation.
Loading