diff --git a/extensions/diffs/src/render.ts b/extensions/diffs/src/render.ts index 5360b2f46c7..fb3d089c90a 100644 --- a/extensions/diffs/src/render.ts +++ b/extensions/diffs/src/render.ts @@ -150,6 +150,16 @@ function buildImageRenderOptions(options: DiffRenderOptions): DiffRenderOptions }; } +function buildRenderVariants(options: DiffRenderOptions): { + viewerOptions: DiffViewerOptions; + imageOptions: DiffViewerOptions; +} { + return { + viewerOptions: buildDiffOptions(options), + imageOptions: buildDiffOptions(buildImageRenderOptions(options)), + }; +} + function normalizeSupportedLanguage(value?: string): SupportedLanguages | undefined { const normalized = value?.trim(); return normalized ? (normalized as SupportedLanguages) : undefined; @@ -298,6 +308,35 @@ function buildHtmlDocument(params: { `; } +type RenderedSection = { + viewer: string; + image: string; +}; + +function buildRenderedSection(params: { + viewerPrerenderedHtml: string; + imagePrerenderedHtml: string; + payload: Omit; +}): RenderedSection { + return { + viewer: renderDiffCard({ + prerenderedHTML: params.viewerPrerenderedHtml, + ...params.payload, + }), + image: renderStaticDiffCard(params.imagePrerenderedHtml), + }; +} + +function buildRenderedBodies(sections: ReadonlyArray): { + viewerBodyHtml: string; + imageBodyHtml: string; +} { + return { + viewerBodyHtml: sections.map((section) => section.viewer).join("\n"), + imageBodyHtml: sections.map((section) => section.image).join("\n"), + }; +} + async function renderBeforeAfterDiff( input: Extract, options: DiffRenderOptions, @@ -314,33 +353,35 @@ async function renderBeforeAfterDiff( contents: input.after, ...(lang ? { lang } : {}), }; - const viewerPayloadOptions = buildDiffOptions(options); - const imagePayloadOptions = buildDiffOptions(buildImageRenderOptions(options)); + const { viewerOptions, imageOptions } = buildRenderVariants(options); const [viewerResult, imageResult] = await Promise.all([ preloadMultiFileDiff({ oldFile, newFile, - options: viewerPayloadOptions, + options: viewerOptions, }), preloadMultiFileDiff({ oldFile, newFile, - options: imagePayloadOptions, + options: imageOptions, }), ]); - - return { - viewerBodyHtml: renderDiffCard({ - prerenderedHTML: viewerResult.prerenderedHTML, + const section = buildRenderedSection({ + viewerPrerenderedHtml: viewerResult.prerenderedHTML, + imagePrerenderedHtml: imageResult.prerenderedHTML, + payload: { oldFile: viewerResult.oldFile, newFile: viewerResult.newFile, - options: viewerPayloadOptions, + options: viewerOptions, langs: buildPayloadLanguages({ oldFile: viewerResult.oldFile, newFile: viewerResult.newFile, }), - }), - imageBodyHtml: renderStaticDiffCard(imageResult.prerenderedHTML), + }, + }); + + return { + ...buildRenderedBodies([section]), fileCount: 1, }; } @@ -365,36 +406,34 @@ async function renderPatchDiff( throw new Error(`Patch input is too large to render (max ${MAX_PATCH_TOTAL_LINES} lines).`); } - const viewerPayloadOptions = buildDiffOptions(options); - const imagePayloadOptions = buildDiffOptions(buildImageRenderOptions(options)); + const { viewerOptions, imageOptions } = buildRenderVariants(options); const sections = await Promise.all( files.map(async (fileDiff) => { const [viewerResult, imageResult] = await Promise.all([ preloadFileDiff({ fileDiff, - options: viewerPayloadOptions, + options: viewerOptions, }), preloadFileDiff({ fileDiff, - options: imagePayloadOptions, + options: imageOptions, }), ]); - return { - viewer: renderDiffCard({ - prerenderedHTML: viewerResult.prerenderedHTML, + return buildRenderedSection({ + viewerPrerenderedHtml: viewerResult.prerenderedHTML, + imagePrerenderedHtml: imageResult.prerenderedHTML, + payload: { fileDiff: viewerResult.fileDiff, - options: viewerPayloadOptions, + options: viewerOptions, langs: buildPayloadLanguages({ fileDiff: viewerResult.fileDiff }), - }), - image: renderStaticDiffCard(imageResult.prerenderedHTML), - }; + }, + }); }), ); return { - viewerBodyHtml: sections.map((section) => section.viewer).join("\n"), - imageBodyHtml: sections.map((section) => section.image).join("\n"), + ...buildRenderedBodies(sections), fileCount: files.length, }; } diff --git a/extensions/diffs/src/tool.ts b/extensions/diffs/src/tool.ts index 862fd2b0d56..1578c6e1e36 100644 --- a/extensions/diffs/src/tool.ts +++ b/extensions/diffs/src/tool.ts @@ -187,9 +187,10 @@ export function createDiffsTool(params: { content: [ { type: "text", - text: - `Diff ${image.format.toUpperCase()} generated at: ${artifactFile.path}\n` + - "Use the `message` tool with `path` or `filePath` to send this file.", + text: buildFileArtifactMessage({ + format: image.format, + filePath: artifactFile.path, + }), }, ], details: buildArtifactDetails({ @@ -257,10 +258,11 @@ export function createDiffsTool(params: { content: [ { type: "text", - text: - `Diff viewer: ${viewerUrl}\n` + - `Diff ${image.format.toUpperCase()} generated at: ${artifactFile.path}\n` + - "Use the `message` tool with `path` or `filePath` to send this file.", + text: buildFileArtifactMessage({ + format: image.format, + filePath: artifactFile.path, + viewerUrl, + }), }, ], details: buildArtifactDetails({ @@ -330,6 +332,17 @@ function buildArtifactDetails(params: { }; } +function buildFileArtifactMessage(params: { + format: DiffOutputFormat; + filePath: string; + viewerUrl?: string; +}): string { + const lines = params.viewerUrl ? [`Diff viewer: ${params.viewerUrl}`] : []; + lines.push(`Diff ${params.format.toUpperCase()} generated at: ${params.filePath}`); + lines.push("Use the `message` tool with `path` or `filePath` to send this file."); + return lines.join("\n"); +} + async function renderDiffArtifactFile(params: { screenshotter: DiffScreenshotter; store: DiffArtifactStore; diff --git a/extensions/diffs/src/viewer-client.ts b/extensions/diffs/src/viewer-client.ts index 8e54c298bc7..14ffaed7cbd 100644 --- a/extensions/diffs/src/viewer-client.ts +++ b/extensions/diffs/src/viewer-client.ts @@ -106,39 +106,9 @@ function createToolbarButton(params: { } function applyToolbarButtonStyles(button: HTMLButtonElement, active: boolean): void { - button.style.display = "inline-flex"; - button.style.alignItems = "center"; - button.style.justifyContent = "center"; - button.style.width = "24px"; - button.style.height = "24px"; - button.style.padding = "0"; - button.style.margin = "0"; - button.style.border = "0"; - button.style.borderRadius = "0"; - button.style.background = "transparent"; - button.style.boxShadow = "none"; - button.style.lineHeight = "0"; - button.style.cursor = "pointer"; - button.style.overflow = "visible"; - button.style.flex = "0 0 auto"; - button.style.opacity = active ? "0.92" : "0.6"; button.style.color = viewerState.theme === "dark" ? "rgba(226, 232, 240, 0.74)" : "rgba(15, 23, 42, 0.52)"; - - const svg = button.querySelector("svg"); - if (!svg) { - return; - } - svg.style.display = "block"; - svg.style.width = "16px"; - svg.style.height = "16px"; - svg.style.minWidth = "16px"; - svg.style.minHeight = "16px"; - svg.style.overflow = "visible"; - svg.style.flex = "0 0 auto"; - svg.style.color = "inherit"; - svg.style.fill = "currentColor"; - svg.style.pointerEvents = "none"; + button.dataset.active = String(active); } function splitIcon(): string { @@ -193,11 +163,6 @@ function themeIcon(theme: DiffTheme): string { function createToolbar(): HTMLElement { const toolbar = document.createElement("div"); toolbar.className = "oc-diff-toolbar"; - toolbar.style.display = "inline-flex"; - toolbar.style.alignItems = "center"; - toolbar.style.gap = "6px"; - toolbar.style.marginInlineStart = "6px"; - toolbar.style.flex = "0 0 auto"; toolbar.append( createToolbarButton({