mirror of
https://github.com/baairon/torlink.git
synced 2026-07-08 18:28:22 +02:00
fix: leave a row of slack below the results panel (#30)
Move the results panel height into a tested resultsPanelOuter helper so the view stays one row short of the overflow:hidden body, matching Downloads and Seeding. Fixes #21.
This commit is contained in:
@@ -7,7 +7,7 @@ import { Panel } from "./Panel";
|
||||
import { Rule } from "./Rule";
|
||||
import { useConcurrentSearch } from "../hooks/useConcurrentSearch";
|
||||
import { getSource, SOURCES } from "../../sources/registry";
|
||||
import { wrapStep, windowStart } from "../move";
|
||||
import { wrapStep, windowStart, resultsPanelOuter } from "../move";
|
||||
import { sortResults, nextSort, sortLabel, sortArrow, type Sort, type SortField } from "../sort";
|
||||
import { COLOR, GUTTER, ICON, SOURCE_STYLE } from "../theme";
|
||||
import { cleanText, formatBytes, formatRelative, truncate } from "../../util/format";
|
||||
@@ -155,7 +155,7 @@ export function Results() {
|
||||
const clamped = Math.min(cursor, Math.max(0, results.length - 1));
|
||||
|
||||
const searchH = 3;
|
||||
const panelOuter = Math.max(5, listRows - searchH - 1);
|
||||
const panelOuter = resultsPanelOuter(listRows, searchH);
|
||||
const listHeight = Math.max(3, panelOuter - 4);
|
||||
const pageJump = Math.max(1, listHeight - 1);
|
||||
|
||||
|
||||
+28
-1
@@ -1,5 +1,5 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { wrapStep, windowStart } from "./move";
|
||||
import { wrapStep, windowStart, resultsPanelOuter } from "./move";
|
||||
|
||||
describe("wrapStep", () => {
|
||||
it("wraps around both ends", () => {
|
||||
@@ -18,3 +18,30 @@ describe("windowStart", () => {
|
||||
expect(windowStart(2, 4, 10)).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("resultsPanelOuter", () => {
|
||||
// The results view is: search bar (searchH rows) + a 1-row gap + the panel.
|
||||
const searchH = 3;
|
||||
const resultsHeight = (listRows: number): number =>
|
||||
searchH + 1 + resultsPanelOuter(listRows, searchH);
|
||||
|
||||
it("leaves a row of slack so results never exactly fill the body box (issue #21)", () => {
|
||||
// An exact fit inside the parent overflow:hidden body desyncs Ink's
|
||||
// incremental renderer and swallows a row while scrolling. The view must
|
||||
// stay strictly shorter than the row budget it is given.
|
||||
for (let listRows = 12; listRows <= 80; listRows++) {
|
||||
expect(resultsHeight(listRows)).toBeLessThan(listRows);
|
||||
}
|
||||
});
|
||||
|
||||
it("uses exactly one row of slack, matching Downloads/Seeding (listRows - 1)", () => {
|
||||
for (let listRows = 12; listRows <= 80; listRows++) {
|
||||
expect(resultsHeight(listRows)).toBe(listRows - 1);
|
||||
}
|
||||
});
|
||||
|
||||
it("clamps to a minimum usable panel height on tiny terminals", () => {
|
||||
expect(resultsPanelOuter(4, searchH)).toBe(5);
|
||||
expect(resultsPanelOuter(0, searchH)).toBe(5);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,3 +8,18 @@ export function windowStart(cursor: number, total: number, height: number): numb
|
||||
const half = Math.floor(height / 2);
|
||||
return Math.max(0, Math.min(cursor - half, total - height));
|
||||
}
|
||||
|
||||
/**
|
||||
* Outer height of the results panel given the body's row budget.
|
||||
*
|
||||
* The results view stacks a search bar (`searchH` rows) + a one-row gap on top
|
||||
* of the panel. We intentionally subtract one extra row so the view never
|
||||
* *exactly* fills the parent `overflow: "hidden"` body box. An exact fit
|
||||
* desyncs Ink's incremental terminal renderer and makes it swallow a row while
|
||||
* scrolling — the "highlighted numbering is wrong" bug (issue #21). Downloads
|
||||
* and Seeding already leave this slack via `listRows - 1`; this keeps Results
|
||||
* consistent with them.
|
||||
*/
|
||||
export function resultsPanelOuter(listRows: number, searchH: number): number {
|
||||
return Math.max(5, listRows - searchH - 2);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user