console: the immediate action lives top-right, not below the fold
"What do I do now" was answered only by scrolling past the metrics and stage rail to the Next step panel. When this user owns the next step it now sits in the header top-right as a prominent amber button — where the eye goes for the next move — and pressing it opens the form and scrolls to it. When nothing is owed, the passive status stays there instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
60f6c97201
commit
17561f3f73
@ -319,6 +319,25 @@ export default function Lead() {
|
||||
// anyway; showing them a row of buttons that all 403 reads as a broken app
|
||||
// rather than as a control.
|
||||
const actions = actionsFor(roles, stage?.uid)
|
||||
|
||||
// THE ONE THING THIS USER MUST DO, promoted to the header. "What do I do
|
||||
// now" is the first question an operator asks of a lead, and it was answered
|
||||
// only by scrolling past the metrics and the stage rail to the Next step
|
||||
// panel. When this user has an action, it belongs top-right, where the eye
|
||||
// goes for the next move; when they do not, the passive status stays there
|
||||
// instead. `role: 'do'` is the committing step — never a re-run or a
|
||||
// recovery lever, which must not be dressed as the thing to do.
|
||||
const acceptedAlready = Boolean(row.acceptance_ref)
|
||||
const primaryAction = actions.find(
|
||||
(a) => a.role === 'do' && !(acceptedAlready && a.uid === 'zk-act-accept'),
|
||||
) || null
|
||||
const goToAction = () => {
|
||||
if (!primaryAction) return
|
||||
setOpen(primaryAction.uid)
|
||||
// Let the form mount, then bring the working surface into view.
|
||||
requestAnimationFrame(() =>
|
||||
document.getElementById('lead-next')?.scrollIntoView({ behavior: 'smooth', block: 'center' }))
|
||||
}
|
||||
const fieldCount = groups.reduce((n, [, shown]) => n + shown.length, 0)
|
||||
|
||||
// Built from the SAME rows the full file renders, so the two can never
|
||||
@ -406,7 +425,18 @@ export default function Lead() {
|
||||
{/* WHOSE MOVE IT IS. The stage name is in the rail below; this says
|
||||
who holds the lead right now, which is the question the header is
|
||||
really being asked. The customer tone reuses the teal cust palette. */}
|
||||
{holds ? (
|
||||
{primaryAction ? (
|
||||
/* YOUR MOVE. When this user owns the next step, the header carries it
|
||||
as the prominent thing — amber, because it is waiting on a person —
|
||||
and pressing it opens the form below and scrolls to it. */
|
||||
<button type="button" className="cta" onClick={goToAction}>
|
||||
<span className="cta__txt">
|
||||
<small>Your move</small>
|
||||
<b>{primaryAction.label}</b>
|
||||
</span>
|
||||
<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M3 8h9M8.5 4.5 12 8l-3.5 3.5" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"/></svg>
|
||||
</button>
|
||||
) : holds ? (
|
||||
<div className={'holds holds--' + (holds.pillTone === 'cust' ? 'cust' : holds.tone)}>
|
||||
<span className="holds__puck" aria-hidden="true">
|
||||
{holds.tone === 'ai' ? (
|
||||
@ -622,7 +652,7 @@ export default function Lead() {
|
||||
if (!step.length && !again.length && !extras.length) return null
|
||||
|
||||
return (
|
||||
<div className="panel">
|
||||
<div className="panel" id="lead-next">
|
||||
<div className="panel__head">
|
||||
<div>
|
||||
<h2 className="panel__title">Next step</h2>
|
||||
|
||||
@ -1798,3 +1798,35 @@
|
||||
|
||||
.holds--cust .holds__puck { background: var(--zk-teal); box-shadow: 0 0 0 4px var(--zk-teal-tint); }
|
||||
.holds--cust .holds__txt small { color: var(--zk-teal-ink); }
|
||||
|
||||
/* ── Your move: the immediate action, in the header ───────────────────────
|
||||
The one thing this user must do, promoted top-right where the eye looks for
|
||||
the next move. Amber because it is waiting on a person; pressing it opens
|
||||
the form and scrolls to it. When nothing is owed, the passive holds status
|
||||
sits here instead. */
|
||||
.cta {
|
||||
flex: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--sp-3);
|
||||
padding: var(--sp-3) var(--sp-4) var(--sp-3) var(--sp-5);
|
||||
border: 0;
|
||||
border-radius: var(--r-md);
|
||||
background: var(--zk-amber);
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
box-shadow: var(--sh-sm);
|
||||
transition: background var(--t-fast), box-shadow var(--t-fast), transform var(--t-fast);
|
||||
}
|
||||
.cta:hover { background: var(--zk-amber-ink); box-shadow: var(--sh-md); }
|
||||
.cta:focus-visible { outline: 2px solid var(--zk-amber-ink); outline-offset: 2px; }
|
||||
.cta__txt { display: flex; flex-direction: column; align-items: flex-start; line-height: 1.2; }
|
||||
.cta__txt small {
|
||||
font-size: var(--fs-3xs);
|
||||
font-weight: var(--fw-semi);
|
||||
letter-spacing: .08em;
|
||||
text-transform: uppercase;
|
||||
opacity: .82;
|
||||
}
|
||||
.cta__txt b { font-size: var(--fs-sm); font-weight: var(--fw-semi); }
|
||||
.cta svg { width: 16px; height: 16px; flex: none; }
|
||||
|
||||
Loading…
Reference in New Issue
Block a user