Files
paseo/packages/app/src/git/diff-document/palette.ts
T
Mohamed Boudra 3998ea11d9 Keep large diffs responsive across web and mobile (#4174)
* perf(app): keep large diffs responsive

Render file headers on the canvas and bound expensive text shaping to the active viewport while preserving sticky, hover, and horizontal-scroll behavior. Let native scroll cancellation arbitrate header presses so finger scrolling cannot expand files.

* test(app): assert canvas diff header accessibility

* test(app): assert canvas diff header semantics
2026-09-01 23:52:11 +02:00

68 lines
2.7 KiB
TypeScript

import type { Theme } from "@/styles/theme";
import { hexColorWithAlpha } from "@/utils/color";
import type { DiffCell, DiffPalette } from "./types";
export function createDiffPalette(theme: Theme): DiffPalette {
return {
surface: theme.colors.surface0,
headerSurface: theme.colors.surface0,
border: theme.colors.border,
foreground: theme.colors.foreground,
foregroundMuted: theme.colors.foregroundMuted,
addition: theme.colors.statusSuccess,
deletion: theme.colors.statusDanger,
additionBackground: hexColorWithAlpha(theme.colors.statusSuccess, 0.15),
deletionBackground: hexColorWithAlpha(theme.colors.statusDanger, 0.1),
emptyBackground: theme.colors.surface0,
selection: theme.colors.terminal.blue,
headerActiveSurface: theme.colors.surface1,
headerBorder: theme.colors.borderAccent,
statusSuccess: theme.colors.statusSuccess,
statusDanger: theme.colors.statusDanger,
statusWarning: theme.colors.statusWarning,
syntax: theme.colors.syntax,
};
}
export function retainDiffPalette(previous: DiffPalette, next: DiffPalette): DiffPalette {
if (
previous.surface !== next.surface ||
previous.headerSurface !== next.headerSurface ||
previous.border !== next.border ||
previous.foreground !== next.foreground ||
previous.foregroundMuted !== next.foregroundMuted ||
previous.addition !== next.addition ||
previous.deletion !== next.deletion ||
previous.additionBackground !== next.additionBackground ||
previous.deletionBackground !== next.deletionBackground ||
previous.emptyBackground !== next.emptyBackground ||
previous.selection !== next.selection ||
previous.headerActiveSurface !== next.headerActiveSurface ||
previous.headerBorder !== next.headerBorder ||
previous.statusSuccess !== next.statusSuccess ||
previous.statusDanger !== next.statusDanger ||
previous.statusWarning !== next.statusWarning ||
!sameColorMap(previous.syntax, next.syntax)
) {
return next;
}
return previous;
}
function sameColorMap(left: Record<string, string>, right: Record<string, string>): boolean {
const leftKeys = Object.keys(left);
const rightKeys = Object.keys(right);
return leftKeys.length === rightKeys.length && leftKeys.every((key) => left[key] === right[key]);
}
export function codeTextColor(cell: DiffCell, palette: DiffPalette): string {
return cell.type === "header" ? palette.foregroundMuted : palette.foreground;
}
export function codeLineNumberTone(cell: DiffCell): "addition" | "deletion" | "foregroundMuted" {
"worklet";
if (cell.type === "add") return "addition";
if (cell.type === "remove") return "deletion";
return "foregroundMuted";
}