From e9bb4e20e2c94d163e445572ab824c1cf316a5cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Flor=C3=AAncio?= Date: Tue, 28 Jul 2026 16:38:56 +0100 Subject: [PATCH] feat(walkthrough): stabilize navigation footer (#2002) --- apps/backend/cmd/mock-agent/scenarios.go | 19 ++- .../diff/walkthrough-floating-window.tsx | 4 +- .../components/diff/walkthrough-step-card.tsx | 35 ++++-- .../use-codemirror-walkthrough-range.test.ts | 118 ++++++++++++++++++ .../use-codemirror-walkthrough-range.ts | 3 +- .../use-monaco-walkthrough-range.test.ts | 89 ++++++++++++- .../monaco/use-monaco-walkthrough-range.ts | 3 +- .../tests/review/mobile-walkthrough.spec.ts | 12 ++ apps/web/e2e/tests/review/walkthrough.spec.ts | 10 ++ .../walkthrough-navigation-layout/plan.md | 78 ++++++++++++ .../task-01-stable-navigation-footer.md | 70 +++++++++++ docs/specs/INDEX.md | 1 + .../walkthrough-navigation-layout/spec.md | 48 +++++++ 13 files changed, 471 insertions(+), 19 deletions(-) create mode 100644 apps/web/components/editors/codemirror/use-codemirror-walkthrough-range.test.ts create mode 100644 docs/plans/walkthrough-navigation-layout/plan.md create mode 100644 docs/plans/walkthrough-navigation-layout/task-01-stable-navigation-footer.md create mode 100644 docs/specs/walkthrough-navigation-layout/spec.md diff --git a/apps/backend/cmd/mock-agent/scenarios.go b/apps/backend/cmd/mock-agent/scenarios.go index 79a9e9aef1..fae471ee3b 100644 --- a/apps/backend/cmd/mock-agent/scenarios.go +++ b/apps/backend/cmd/mock-agent/scenarios.go @@ -898,7 +898,7 @@ func setupWalkthroughFiles(e *emitter, prefix string) bool { } runGitCmd := makeGitRunner(wd) - fixtures := []string{"walkthrough_a.txt", "walkthrough_b.txt", "walkthrough_c.txt", "walkthrough_base.txt"} + fixtures := []string{"walkthrough_a.txt", "walkthrough_b.txt", "walkthrough_c.txt"} _ = runGitCmd(append([]string{"rm", "--force"}, fixtures...)...) _ = runGitCmd("commit", "-m", "cleanup walkthrough fixtures") @@ -911,11 +911,24 @@ func setupWalkthroughFiles(e *emitter, prefix string) bool { "line 1: B\nline 2: BASE\nline 3: BASE\nline 4: WALKTHROUGH_CHANGE_B\nline 5: WALKTHROUGH_CHANGE_B\n") ok = ok && writeWalkthroughFile(e, runGitCmd, prefix, "walkthrough_c.txt", "line 1: C\nline 2: BASE\n", "line 1: C\nline 2: WALKTHROUGH_CHANGE_C\n") - ok = ok && writeWalkthroughFile(e, runGitCmd, prefix, "walkthrough_base.txt", - "line 1: WALKTHROUGH_UNCHANGED\nline 2: supporting context\n", "") + const baseContent = "line 1: WALKTHROUGH_UNCHANGED\nline 2: seeded on main\n" + if !walkthroughBaseIsClean(runGitCmd, baseContent) { + _ = runGitCmd("rm", "--force", "walkthrough_base.txt") + _ = runGitCmd("commit", "-m", "cleanup walkthrough base fixture") + ok = ok && writeWalkthroughFile(e, runGitCmd, prefix, "walkthrough_base.txt", baseContent, "") + } return ok } +func walkthroughBaseIsClean(runGitCmd func(args ...string) error, expectedContent string) bool { + content, err := os.ReadFile("walkthrough_base.txt") + return err == nil && + string(content) == expectedContent && + runGitCmd("ls-files", "--error-unmatch", "walkthrough_base.txt") == nil && + runGitCmd("diff", "--quiet", "--", "walkthrough_base.txt") == nil && + runGitCmd("diff", "--cached", "--quiet", "--", "walkthrough_base.txt") == nil +} + func emitWalkthroughTour(e *emitter, doneText string) { fixedDelay(100) e.text("Let me walk you through the change.") diff --git a/apps/web/components/diff/walkthrough-floating-window.tsx b/apps/web/components/diff/walkthrough-floating-window.tsx index 9a3332cef4..26471ca714 100644 --- a/apps/web/components/diff/walkthrough-floating-window.tsx +++ b/apps/web/components/diff/walkthrough-floating-window.tsx @@ -236,13 +236,13 @@ export function WalkthroughFloatingWindow({ data-testid="walkthrough-floating" data-mobile-variant="bottom-sheet" className={cn( - "fixed inset-x-2 bottom-[calc(0.5rem+var(--app-status-bar-height))] z-[43] max-h-[calc(100dvh-1rem)] overflow-y-auto rounded-xl", + "fixed inset-x-2 bottom-[calc(0.5rem+var(--app-status-bar-height)+env(safe-area-inset-bottom,0px))] z-[43] max-h-[calc(100dvh-1rem-env(safe-area-inset-bottom,0px))] overflow-hidden rounded-xl", "sm:inset-x-auto sm:bottom-auto sm:w-[400px] sm:max-w-[calc(100vw-2rem)]", )} style={isDesktop && position ? { left: position.x, top: position.y } : undefined} onPointerDown={onPointerDown} > - + ); diff --git a/apps/web/components/diff/walkthrough-step-card.tsx b/apps/web/components/diff/walkthrough-step-card.tsx index 080e296ae1..79e9575160 100644 --- a/apps/web/components/diff/walkthrough-step-card.tsx +++ b/apps/web/components/diff/walkthrough-step-card.tsx @@ -20,6 +20,7 @@ import { import type { TaskWalkthrough, WalkthroughStep } from "@/lib/types/http"; import type { WalkthroughComment } from "@/lib/state/slices/comments"; import { CommentForm } from "./comment-form"; +import { cn } from "@kandev/ui/lib/utils"; export const WALKTHROUGH_STEP_BODY_CLASS = "prose prose-sm dark:prose-invert max-w-none text-left text-sm leading-6 [overflow-wrap:anywhere] [text-align:left] [&_li]:text-left [&_p]:my-2 [&_p]:text-left"; @@ -103,7 +104,10 @@ function StepNavigation({ onNext: () => void; }) { return ( -
+