From eaae2dd4ce3a400b44b4347bd51128baa2a9f0cd Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Sun, 31 May 2026 20:23:35 -0700 Subject: [PATCH] Polish CLI feature tip terminal transition (#4344) Co-authored-by: Orca --- .../feature-tips/CliFeatureTipVisual.tsx | 103 ++++++++ .../feature-tips/CliSkillSetupTerminal.tsx | 54 +++++ .../feature-tips/FeatureTipsModal.tsx | 224 +++++++----------- 3 files changed, 237 insertions(+), 144 deletions(-) create mode 100644 src/renderer/src/components/feature-tips/CliFeatureTipVisual.tsx create mode 100644 src/renderer/src/components/feature-tips/CliSkillSetupTerminal.tsx diff --git a/src/renderer/src/components/feature-tips/CliFeatureTipVisual.tsx b/src/renderer/src/components/feature-tips/CliFeatureTipVisual.tsx new file mode 100644 index 000000000..55e1e3531 --- /dev/null +++ b/src/renderer/src/components/feature-tips/CliFeatureTipVisual.tsx @@ -0,0 +1,103 @@ +import { useEffect, useState, type JSX } from 'react' +import { AgentsOrchestrationVisual } from '@/components/feature-wall/AgentsOrchestrationVisual' +import { + ORCHESTRATION_CLI_COMMAND_LOOP_MS, + ORCHESTRATION_CLI_COMMAND_TIMINGS_MS +} from '@/components/feature-wall/agents-orchestration/orchestration-types' +import { usePrefersReducedMotion } from '@/components/feature-wall/feature-wall-modal-helpers' + +const CLI_AGENT_COMMANDS = [ + 'orca worktree create --name auth-pr-1', + 'orca worktree create --name auth-pr-2', + 'orca orchestration dispatch --task pr1 --to w1', + 'orca orchestration dispatch --task pr2 --to w2' +] + +export function CliFeatureTipVisual(): JSX.Element { + const reducedMotion = usePrefersReducedMotion() + const [animatedVisibleCommandCount, setAnimatedVisibleCommandCount] = useState(0) + // Why: reduced-motion users should see the static completed state without a + // post-render state repair; only the animated path needs timer-backed state. + const visibleCommandCount = reducedMotion + ? CLI_AGENT_COMMANDS.length + : animatedVisibleCommandCount + + useEffect(() => { + if (reducedMotion) { + return + } + + let cancelled = false + const timeouts: number[] = [] + const later = (fn: () => void, ms: number): void => { + timeouts.push(window.setTimeout(() => !cancelled && fn(), ms)) + } + + // Why: terminal lines mirror the orchestration tour beat timings so the + // shell shows each command as the parent agent runs it. + const runOnce = (): void => { + setAnimatedVisibleCommandCount(0) + ORCHESTRATION_CLI_COMMAND_TIMINGS_MS.forEach((ms, index) => { + later(() => setAnimatedVisibleCommandCount(index + 1), ms) + }) + later(runOnce, ORCHESTRATION_CLI_COMMAND_LOOP_MS) + } + + runOnce() + return () => { + cancelled = true + timeouts.forEach((id) => window.clearTimeout(id)) + } + }, [reducedMotion]) + + return ( +