Skip to content

Commit 04d4676

Browse files
icecrasher321claude
andcommitted
improvement(canvas): fill the running sweep one way, and tighten its mark
The sweep drained back to empty after each pass, which reads as undoing the progress the block is making. It fills left to right and starts over. The direction flag goes with it — the state is just the count now. The slanted mark also sat too far off its neighbours. Slant and tightness trade against each other here: the transparent wedge has to be at least as wide as the edge's horizontal travel, or the cut clips a corner instead of crossing the slot. Leaning 7° off vertical instead of 17° travels 2.9px across the 24px slot rather than 7.3px, which brings the wedge in from 26% to 12% — 3.2px a side against 7.8px, so the gap between marks drops from ~17.6px to ~8.4px with the slant still crossing cleanly. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent d4b3f87 commit 04d4676

3 files changed

Lines changed: 32 additions & 47 deletions

File tree

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/action-bar/action-bar.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,19 +53,26 @@ const ACTION_BUTTON_STYLES = [
5353
* win a specificity race against it. The stops keep `--surface-2` exactly — only
5454
* the shape changes.
5555
*
56+
* Slant and tightness trade against each other: the transparent wedge has to be
57+
* at least as wide as the edge's horizontal travel, or the cut clips a corner
58+
* instead of crossing the slot cleanly. 97deg leans the edge 7° off vertical,
59+
* which travels 2.9px over the 24px slot and lets the wedge come in to 12% —
60+
* 3.2px a side, against the 7.8px a 107deg lean needed. Steepen the angle and
61+
* both stops have to move outward with it.
62+
*
5663
* Every variant is spelled out: Tailwind's JIT reads literal class strings, so a
5764
* `hover-hover:${FILL}` built at runtime compiles to no CSS at all. The hover
5865
* and motion-reduce entries also clear the base `hover-hover:bg-*` COLOR, which
5966
* a background-image cannot override and which would otherwise fill the slot
6067
* back in behind the band.
6168
*/
6269
const RUNNING_SWEEP_FILL = [
63-
'!bg-[linear-gradient(107deg,transparent_26%,var(--surface-2)_26%,var(--surface-2)_74%,transparent_74%)]',
64-
'hover-hover:!bg-[linear-gradient(107deg,transparent_26%,var(--surface-2)_26%,var(--surface-2)_74%,transparent_74%)]',
70+
'!bg-[linear-gradient(97deg,transparent_12%,var(--surface-2)_12%,var(--surface-2)_88%,transparent_88%)]',
71+
'hover-hover:!bg-[linear-gradient(97deg,transparent_12%,var(--surface-2)_12%,var(--surface-2)_88%,transparent_88%)]',
6572
].join(' ')
6673

6774
const RUNNING_SWEEP_FILL_STATIC =
68-
'motion-reduce:!bg-[linear-gradient(107deg,transparent_26%,var(--surface-2)_26%,var(--surface-2)_74%,transparent_74%)]'
75+
'motion-reduce:!bg-[linear-gradient(97deg,transparent_12%,var(--surface-2)_12%,var(--surface-2)_88%,transparent_88%)]'
6976

7077
const ICON_SIZE = 'size-[14px]'
7178

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,21 @@
11
import { describe, expect, it } from 'vitest'
2-
import {
3-
advanceActionSweep,
4-
INITIAL_ACTION_SWEEP_STATE,
5-
} from '@/app/workspace/[workspaceId]/w/[workflowId]/components/action-bar/use-running-action-sweep'
2+
import { advanceActionSweep } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/action-bar/use-running-action-sweep'
63

74
describe('advanceActionSweep', () => {
85
it('fills action slots cumulatively from left to right', () => {
9-
const first = advanceActionSweep(INITIAL_ACTION_SWEEP_STATE, 3)
6+
const first = advanceActionSweep(0, 3)
107
const second = advanceActionSweep(first, 3)
118
const third = advanceActionSweep(second, 3)
129

13-
expect([first.filledCount, second.filledCount, third.filledCount]).toEqual([1, 2, 3])
14-
expect(third.direction).toBe(-1)
10+
expect([first, second, third]).toEqual([1, 2, 3])
1511
})
1612

17-
it('empties action slots from right to left before restarting', () => {
18-
const second = advanceActionSweep({ filledCount: 3, direction: -1 }, 3)
19-
const first = advanceActionSweep(second, 3)
20-
const empty = advanceActionSweep(first, 3)
21-
22-
expect([second.filledCount, first.filledCount, empty.filledCount]).toEqual([2, 1, 0])
23-
expect(empty.direction).toBe(1)
13+
it('restarts from empty once full, rather than draining back', () => {
14+
expect(advanceActionSweep(3, 3)).toBe(0)
15+
expect(advanceActionSweep(0, 3)).toBe(1)
2416
})
2517

2618
it('stays empty when there are no action slots', () => {
27-
expect(advanceActionSweep({ filledCount: 2, direction: -1 }, 0)).toEqual(
28-
INITIAL_ACTION_SWEEP_STATE
29-
)
19+
expect(advanceActionSweep(2, 0)).toBe(0)
3020
})
3121
})

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/action-bar/use-running-action-sweep.ts

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,47 +2,35 @@ import { useEffect, useState } from 'react'
22

33
const ACTION_SWEEP_INTERVAL_MS = 160
44

5-
interface ActionSweepState {
6-
filledCount: number
7-
direction: 1 | -1
5+
/**
6+
* Advances the cumulative action-slot sweep by one frame.
7+
*
8+
* Fills left to right and starts over — it does not drain back. A bar that
9+
* empties itself reads as undoing progress, which is the opposite of what a
10+
* running block is doing.
11+
*/
12+
export function advanceActionSweep(filledCount: number, slotCount: number): number {
13+
if (slotCount <= 0) return 0
14+
return filledCount >= slotCount ? 0 : filledCount + 1
815
}
916

10-
export const INITIAL_ACTION_SWEEP_STATE: ActionSweepState = {
11-
filledCount: 0,
12-
direction: 1,
13-
}
14-
15-
/** Advances the cumulative action-slot sweep by one frame. */
16-
export function advanceActionSweep(state: ActionSweepState, slotCount: number): ActionSweepState {
17-
if (slotCount <= 0) return INITIAL_ACTION_SWEEP_STATE
18-
19-
const nextCount = state.filledCount + state.direction
20-
if (nextCount >= slotCount) {
21-
return { filledCount: slotCount, direction: -1 }
22-
}
23-
if (nextCount <= 0) {
24-
return INITIAL_ACTION_SWEEP_STATE
25-
}
26-
return { filledCount: nextCount, direction: state.direction }
27-
}
28-
29-
/** Runs a cumulative left-to-right, right-to-left sweep while a block executes. */
17+
/** Runs a cumulative left-to-right fill while a block executes. */
3018
export function useRunningActionSweep(isRunning: boolean, slotCount: number): number {
31-
const [state, setState] = useState<ActionSweepState>(INITIAL_ACTION_SWEEP_STATE)
19+
const [filledCount, setFilledCount] = useState(0)
3220

3321
useEffect(() => {
3422
/* After the early return, not before it: every idle ActionBar on the canvas
3523
runs this effect on mount, and scheduling an update there is wasted work.
3624
The `isRunning` guard on the return value already hides a stale count. */
3725
if (!isRunning || slotCount <= 0) return
38-
setState(INITIAL_ACTION_SWEEP_STATE)
26+
setFilledCount(0)
3927

4028
const intervalId = window.setInterval(() => {
41-
setState((current) => advanceActionSweep(current, slotCount))
29+
setFilledCount((current) => advanceActionSweep(current, slotCount))
4230
}, ACTION_SWEEP_INTERVAL_MS)
4331

4432
return () => window.clearInterval(intervalId)
4533
}, [isRunning, slotCount])
4634

47-
return isRunning ? state.filledCount : 0
35+
return isRunning ? filledCount : 0
4836
}

0 commit comments

Comments
 (0)