fix(flows): pin validation panel to viewport bottom while editing

"No issues. Ready to activate." (and the equivalent error count)
sat at the very bottom of the editor. With even a handful of nodes
the panel was below the fold — the user had to scroll past every
node card to see whether they could activate.

Wrap the panel in a sticky-bottom container so the activate-readiness
status follows the user as they scroll. Shadow-xl gives it the lift
to read as "pinned" against the node list behind it.

Side fix while I was in there: the success-state panel used
bg-emerald-500/10 (10% emerald on whatever's behind). Fine when
nothing's behind, but sticky-positioned over a slate-900 node card
the green tint bled through ugly. Switched both states to a
bg-slate-950 base with the severity expressed in the border + text
color only — readable on any backdrop.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Arnas Donauskas 2026-05-22 16:19:19 +03:00
parent 9febfae9b2
commit 47836d2c08
No known key found for this signature in database

View File

@ -657,8 +657,15 @@ export function FlowBuilder({ initialFlow, initialNodes }: FlowBuilderProps) {
)} )}
</section> </section>
{/* Sticky-bottom so the activate-readiness status follows the
user as they scroll through nodes. The parent <main> in the
dashboard shell is the scroll container; this stays pinned
to the viewport bottom (with a 1rem gap) until the page
naturally ends, at which point it falls back into flow. */}
<div className="sticky bottom-4 z-10 shadow-xl shadow-slate-950/60">
<ValidationPanel issues={issues} onJump={jumpToNode} /> <ValidationPanel issues={issues} onJump={jumpToNode} />
</div> </div>
</div>
); );
} }
@ -2041,9 +2048,12 @@ function ValidationPanel({
onJump: (key: string) => void; onJump: (key: string) => void;
}) { }) {
if (issues.length === 0) { if (issues.length === 0) {
// Slate-950 base + emerald accents so the panel stays readable when
// sticky-positioned over scrolled-behind node cards (a translucent
// bg-emerald-500/10 would bleed through ugly).
return ( return (
<div className="flex items-center gap-2 rounded-lg border border-emerald-600/40 bg-emerald-500/10 p-3 text-xs text-emerald-300"> <div className="flex items-center gap-2 rounded-lg border border-emerald-600/50 bg-slate-950 p-3 text-sm font-medium text-emerald-300">
<CircleCheck className="h-4 w-4" /> <CircleCheck className="h-4 w-4 shrink-0" />
No issues. Ready to activate. No issues. Ready to activate.
</div> </div>
); );
@ -2051,7 +2061,12 @@ function ValidationPanel({
const errors = issues.filter((i) => i.severity === "error"); const errors = issues.filter((i) => i.severity === "error");
const warnings = issues.filter((i) => i.severity === "warning"); const warnings = issues.filter((i) => i.severity === "warning");
return ( return (
<div className="rounded-lg border border-slate-800 bg-slate-900 p-3"> <div
className={cn(
"rounded-lg border bg-slate-950 p-3",
errors.length > 0 ? "border-red-500/40" : "border-amber-500/40",
)}
>
<div className="mb-2 flex items-center gap-2 text-xs text-slate-400"> <div className="mb-2 flex items-center gap-2 text-xs text-slate-400">
{errors.length > 0 ? ( {errors.length > 0 ? (
<CircleAlert className="h-4 w-4 text-red-400" /> <CircleAlert className="h-4 w-4 text-red-400" />