Merge pull request #3666 from jeremymcs/fix/notification-overlay-backdrop
fix(gsd): notification overlay backdrop and truncation fixes
This commit is contained in:
commit
bd574d412e
3 changed files with 18 additions and 13 deletions
|
|
@ -34,7 +34,7 @@ describe("compositeOverlays — backdrop", () => {
|
|||
assert.ok(dimmedLine.includes("\x1b[2m"), "base line should be dimmed");
|
||||
});
|
||||
|
||||
it("backdrop uses 256-color dark gray background", () => {
|
||||
it("backdrop uses gray foreground for dimming", () => {
|
||||
const base = ["hello world", "second line"];
|
||||
const overlay = makeEntry(["OV"], {
|
||||
width: 2,
|
||||
|
|
@ -44,11 +44,11 @@ describe("compositeOverlays — backdrop", () => {
|
|||
|
||||
const result = compositeOverlays(base, [overlay], 20, 20, 2);
|
||||
|
||||
// Check a non-overlay line for full backdrop codes
|
||||
// Check a non-overlay line for backdrop codes (dim + gray fg, no bg)
|
||||
const line = result.find((l) => l.includes("second line"));
|
||||
assert.ok(line, "should have a line containing 'second line'");
|
||||
assert.ok(line.includes("\x1b[38;5;242m"), "backdrop should set gray foreground");
|
||||
assert.ok(line.includes("\x1b[48;5;233m"), "backdrop should set dark gray background");
|
||||
assert.ok(line.includes("\x1b[38;5;240m"), "backdrop should set gray foreground");
|
||||
assert.ok(!line.includes("\x1b[48;"), "backdrop should not set background color");
|
||||
});
|
||||
|
||||
it("does not dim when backdrop is false/absent", () => {
|
||||
|
|
|
|||
|
|
@ -325,11 +325,10 @@ export function compositeOverlays(
|
|||
const viewportStart = Math.max(0, workingHeight - termHeight);
|
||||
|
||||
// Apply backdrop dimming if any visible overlay requests it.
|
||||
// Uses dim + dark gray background (256-color 233) so the overlay pops visually.
|
||||
// Uses dim + gray foreground so text fades without painting empty lines.
|
||||
const hasBackdrop = visibleEntries.some((e) => e.options?.backdrop);
|
||||
if (hasBackdrop) {
|
||||
const dimFn = (text: string) =>
|
||||
`\x1b[2m\x1b[38;5;242m\x1b[48;5;233m${text}\x1b[49m\x1b[39m\x1b[22m`;
|
||||
const dimFn = (text: string) => `\x1b[2m\x1b[38;5;240m${text}\x1b[39m\x1b[22m`;
|
||||
for (let i = viewportStart; i < result.length; i++) {
|
||||
if (!isImageLine(result[i]) && result[i].length > 0) {
|
||||
result[i] = applyBackgroundToLine(result[i], termWidth, dimFn);
|
||||
|
|
|
|||
|
|
@ -163,6 +163,12 @@ export class GSDNotificationOverlay {
|
|||
this.scrollOffset = Math.min(this.scrollOffset, maxScroll);
|
||||
const visibleContent = content.slice(this.scrollOffset, this.scrollOffset + visibleContentRows);
|
||||
|
||||
// Pad to consistent height so filter changes don't leave ghost artifacts
|
||||
// (differential renderer can't clear old overlay positions)
|
||||
while (visibleContent.length < maxVisibleRows) {
|
||||
visibleContent.push("");
|
||||
}
|
||||
|
||||
const lines = this.wrapInBox(visibleContent, width);
|
||||
|
||||
this.cachedWidth = width;
|
||||
|
|
@ -252,13 +258,13 @@ export class GSDNotificationOverlay {
|
|||
const time = th.fg("dim", formatTimestamp(entry.ts));
|
||||
const source = entry.source === "workflow-logger" ? th.fg("dim", " [engine]") : "";
|
||||
|
||||
// First line: icon + timestamp + source
|
||||
const msgMaxWidth = contentWidth - 20;
|
||||
const msg = entry.message.length > msgMaxWidth
|
||||
? entry.message.slice(0, msgMaxWidth - 1) + "…"
|
||||
: entry.message;
|
||||
// Measure actual prefix width to truncate message accurately
|
||||
const prefix = `${coloredIcon} ${time}${source} `;
|
||||
const prefixWidth = visibleWidth(prefix);
|
||||
const msgMaxWidth = Math.max(10, contentWidth - prefixWidth);
|
||||
const msg = truncateToWidth(entry.message, msgMaxWidth, "…");
|
||||
|
||||
lines.push(row(`${coloredIcon} ${time}${source} ${msg}`));
|
||||
lines.push(row(`${prefix}${msg}`));
|
||||
}
|
||||
|
||||
return lines;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue