Keep the node ring lapping while the node is running
Playwright Tests / test-playwright (1, 2) (push) Canceled after 0s
Playwright Tests / test-playwright (2, 2) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Compose Smoke Test / test-compose (push) Canceled after 0s
Playwright Tests / merge-reports (push) Canceled after 0s
Playwright Tests / test-playwright (1, 2) (push) Canceled after 0s
Playwright Tests / test-playwright (2, 2) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Compose Smoke Test / test-compose (push) Canceled after 0s
Playwright Tests / merge-reports (push) Canceled after 0s
The arc was one-shot feedback for an emit, so a node that works for minutes showed nothing after the first half second. A run now holds the ring on the node and laps it until the node stops. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SKL7sUgNWhukDEz95vSMQv
This commit is contained in:
@@ -152,6 +152,7 @@ function FlowNodeComponent({ data, selected }: NodeProps) {
|
||||
.split("\n")
|
||||
const problem = [...new Set(lines)].join("\n")
|
||||
const status = problem ? "error" : live?.status
|
||||
const running = status === "running"
|
||||
const style = STATUS_STYLES[status as keyof typeof STATUS_STYLES]
|
||||
|
||||
return (
|
||||
@@ -160,8 +161,15 @@ function FlowNodeComponent({ data, selected }: NodeProps) {
|
||||
<div className="relative rounded-lg">
|
||||
{/* Remounting on each emit is what restarts the animation, so this is
|
||||
gated on the pulse rather than on the count: a node mounting with a
|
||||
count already in the store would otherwise play it once for free. */}
|
||||
{firing ? <span key={emits} className="node-pulse" /> : null}
|
||||
count already in the store would otherwise play it once for free.
|
||||
A run is not one shot and has no length known in advance, so while one
|
||||
is on the ring laps under a key of its own until the node stops. */}
|
||||
{running || firing ? (
|
||||
<span
|
||||
key={running ? "run" : emits}
|
||||
className={cn("node-pulse", running && "node-pulse-run")}
|
||||
/>
|
||||
) : null}
|
||||
<div
|
||||
className={cn(
|
||||
"relative min-w-[168px] max-w-[220px] rounded-lg border border-border bg-card px-3 py-2.5 shadow-e1 transition-shadow",
|
||||
@@ -186,7 +194,7 @@ function FlowNodeComponent({ data, selected }: NodeProps) {
|
||||
{typeLabel}
|
||||
</span>
|
||||
</span>
|
||||
{status === "running" ? (
|
||||
{running ? (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
|
||||
@@ -109,7 +109,8 @@
|
||||
|
||||
/*
|
||||
* A node that just published something says so, once, and settles: an arc runs
|
||||
* one lap of the rim and goes out.
|
||||
* one lap of the rim and goes out. The same arc, lapping, is a node still at
|
||||
* work.
|
||||
*
|
||||
* The angle has to be registered to be animatable at all — an unregistered
|
||||
* custom property is a token stream, and swapping one for another mid-gradient
|
||||
@@ -169,6 +170,24 @@
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* A node still working keeps the arc going instead: a run lasts as long as it
|
||||
* lasts — a training is minutes — so the lap repeats and never fades out, and
|
||||
* the ring is taken down when the node stops rather than by the animation.
|
||||
* A loop rather than one-shot feedback, so none of the `--duration-*` tokens
|
||||
* fit; the literal is one lap slow enough to read as travel, like the edge
|
||||
* march above.
|
||||
*/
|
||||
.node-pulse.node-pulse-run {
|
||||
animation: node-chase 1.2s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes node-chase {
|
||||
to {
|
||||
--node-pulse-angle: 1turn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Handles are neutral: the one brand-secondary affordance here is Run. */
|
||||
|
||||
Reference in New Issue
Block a user