diff --git a/client/src/components/lanes/LaneChangesPanel.tsx b/client/src/components/lanes/LaneChangesPanel.tsx index 8f87f57b..2f86f96e 100644 --- a/client/src/components/lanes/LaneChangesPanel.tsx +++ b/client/src/components/lanes/LaneChangesPanel.tsx @@ -14,7 +14,7 @@ * is unsaved): Changes folds the unchanged lines away, Whole file * shows them; any other file opens on its read-only diff; a * whole markdown file can also be read rendered (Preview), an HTML - * file shown as the page on Preview, from Changes too + * file shown as the page by Preview beside Whole file * (`HtmlFrame`, its relative CSS, scripts and images read like * downloads), and an * image file is shown as the picture (`GET …/git/raw`) @@ -2061,6 +2061,8 @@ export function LaneChangesPanel({ const dirty = draft !== null && draft !== text?.lines.join("\n"); // Rendered only where the toggle is offered: a whole markdown or HTML file. const mdShown = mdPreview && whole && (isMarkdown(openFile) || isHtml(openFile)); + // The HTML page is showing (the Preview view of the Changes / Whole file / Preview group). + const htmlShown = mdShown && isHtml(openFile); // An HTML page's relative CSS/scripts/images, read like a download — only // from the working tree: a commit's page would get today's files. const htmlFetch = useMemo( @@ -2560,12 +2562,12 @@ export function LaneChangesPanel({ ))} + {/* An HTML file's third view: the page itself. */} + {isHtml(openFile) && ( + + )} )} @@ -2997,21 +3019,17 @@ export function LaneChangesPanel({ {t("changes.annotate")} )} - {/* Offered on Changes too: from there it opens the rendered whole file. */} - {(!whole || text) && !dirty && (isMarkdown(openFile) || isHtml(openFile)) && ( + {/* An HTML file's Preview sits beside Whole file instead. */} + {whole && text && !dirty && isMarkdown(openFile) && ( )} {!local && range !== "commit" && openFile && ( diff --git a/client/src/components/lanes/__tests__/LaneChangesPanel.test.tsx b/client/src/components/lanes/__tests__/LaneChangesPanel.test.tsx index e1d4a506..f207a4fb 100644 --- a/client/src/components/lanes/__tests__/LaneChangesPanel.test.tsx +++ b/client/src/components/lanes/__tests__/LaneChangesPanel.test.tsx @@ -544,7 +544,7 @@ describe("LaneChangesPanel", () => { expect(screen.queryByTestId("lane-file-editor")).toBeNull(); }); - it("opens a whole HTML file as its source, the page after Preview, the source after Raw", async () => { + it("opens a whole HTML file as its source, the page after Preview, the source after Whole file", async () => { vi.mocked(api.lanes.gitTree).mockResolvedValue({ available: true, path: "", @@ -569,7 +569,8 @@ describe("LaneChangesPanel", () => { await user.click(screen.getByTestId("lane-file-preview")); const frame = await screen.findByTestId("html-frame"); expect(frame.getAttribute("srcdoc")).toContain("
deck
"); - await user.click(screen.getByTestId("lane-file-preview")); + expect(screen.getByRole("button", { name: "Preview", pressed: true })).toBeInTheDocument(); + await user.click(screen.getByRole("button", { name: "Whole file", pressed: false })); expect(await screen.findByTestId("lane-file-editor")).toHaveValue("deck
"); expect(screen.queryByTestId("html-frame")).toBeNull(); }); @@ -600,9 +601,9 @@ describe("LaneChangesPanel", () => { const frame = await screen.findByTestId("html-frame"); expect(frame.getAttribute("srcdoc")).toContain("deck
"); expect(frame.getAttribute("sandbox")).not.toContain("allow-same-origin"); - // Back to Changes, then Whole file: the source again, not the page. + // Back to Changes: the diff again, not the page. await user.click(screen.getByRole("button", { name: "Changes", pressed: false })); - await user.click(screen.getByRole("button", { name: "Whole file", pressed: false })); + await screen.findByRole("button", { name: "Changes", pressed: true }); await waitFor(() => expect(screen.queryByTestId("html-frame")).toBeNull()); }); diff --git a/docs/LANES.md b/docs/LANES.md index 2aaf57bc..f0abb8b0 100644 --- a/docs/LANES.md +++ b/docs/LANES.md @@ -678,9 +678,9 @@ reads the workspace's git surface in five modes: least one line tall (`MIN_ROW`), so an empty filler row keeps the two columns aligned. An image file (png, jpg, gif, webp, avif, bmp, ico, svg) is shown as the picture (`/git/raw`), an HTML file (`.html`/`.htm`) opens - like any file (Changes, or Whole file as source) with a **Preview** - button — on Changes too — that shows it as the page; **Raw** goes back to - its source — and a conflicted file opens in the + like any file (Changes, or Whole file as source), and a third view + beside them, **Changes | Whole file | Preview**, shows it as the page — + and a conflicted file opens in the conflict view. The page (here, in a Chat file preview, and on a double-click in the File Explorer, whose right-click menu keeps **Download**) runs in the chat artifact's sandbox (`HtmlFrame.tsx`: