Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/shared/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ export const PERIOD_ORDER: UsageWindow[] = [
];

export const UI_STRINGS = {
dashboardTitle: "Pi Usage Dashboard",
dashboardFooters: {
statistics: [
"[Tab/Shift-Tab] Switch tab",
Expand Down
1 change: 0 additions & 1 deletion src/tui/dashboard-theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ export interface DashboardTheme {
*/
export type DashboardColor =
| "accent"
| "border"
| "borderAccent"
| "borderMuted"
| "selectedBg"
Expand Down
37 changes: 8 additions & 29 deletions src/tui/overlay-render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import type { DashboardTheme } from "./dashboard-theme.ts";
// ── Layout constants ────────────────────────────────────────────────────

const PADDING_X = 2;
const PADDING_Y = 1;

// ── Frame glyphs ────────────────────────────────────────────────────────

Expand Down Expand Up @@ -48,50 +47,30 @@ export function frameContentWidth(width: number): number {
* Wrap content `lines` in a bordered frame box.
*
* Matches the pi-extension-manager's frame rendering:
* - Top/bottom borders with optional title
* - PADDING_Y blank rows above/below content
* - Top/bottom borders
* - Single blank row above/below content
* - PADDING_X space columns on each side of content
* - Overflow truncation with "↓ N more line(s)" when fixedInnerRows is set
*/
export function frame(
lines: string[],
width: number,
theme: DashboardTheme,
fixedInnerRows?: number,
title = "",
): string[] {
const inner = Math.max(1, width - 2);
const contentWidth = frameContentWidth(width);
const border = (s: string) => theme.fg("borderAccent", s);

let body = lines;
if (fixedInnerRows !== undefined && body.length > fixedInnerRows) {
const hidden = body.length - fixedInnerRows + 1;
body = [
...body.slice(0, Math.max(0, fixedInnerRows - 1)),
theme.fg("dim", `↓ ${hidden} more line(s)`),
].slice(0, fixedInnerRows);
}

const blank = `${border(FRAME.v)}${" ".repeat(inner)}${border(FRAME.v)}`;

const top = (): string => {
if (!title) {
return `${border(FRAME.tl)}${border(FRAME.h.repeat(inner))}${border(FRAME.tr)}`;
}
const titleText = ` ${truncateToWidth(title, Math.max(1, inner - 2), "…")} `;
const fill = Math.max(1, inner - visibleWidth(titleText));
return `${border(FRAME.tl)}${theme.fg("accent", titleText)}${border(FRAME.h.repeat(fill))}${border(FRAME.tr)}`;
};

const out = [top()];
for (let i = 0; i < PADDING_Y; i += 1) out.push(blank);
for (const line of body) {
const out = [
`${border(FRAME.tl)}${border(FRAME.h.repeat(inner))}${border(FRAME.tr)}`,
blank,
];
for (const line of lines) {
out.push(
`${border(FRAME.v)}${" ".repeat(PADDING_X)}${pad(line, contentWidth)}${" ".repeat(PADDING_X)}${border(FRAME.v)}`,
);
}
for (let i = 0; i < PADDING_Y; i += 1) out.push(blank);
out.push(blank);
out.push(
`${border(FRAME.bl)}${border(FRAME.h.repeat(inner))}${border(FRAME.br)}`,
);
Expand Down
16 changes: 0 additions & 16 deletions tests/overlay-render.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,22 +62,6 @@ describe("frame", () => {
expect(lines.length).toBe(5); // 1 top + 1 pad + 1 content + 1 pad + 1 bottom
});

it("truncates overflow with indicator when fixedInnerRows is set", () => {
const content = ["line1", "line2", "line3", "line4", "line5"];
const lines = frame(content, 30, noTheme, 3);
const joined = lines.join("\n");
expect(joined).toContain("line1");
expect(joined).toContain("line2");
expect(joined).toContain("more line(s)");
expect(joined).not.toContain("line5");
});

it("renders a title in the top border when provided", () => {
const lines = frame(["content"], 30, noTheme, undefined, "My Title");
expect(lines[0]).toContain("My Title");
expect(lines[0]).toContain("┏");
});

it("pads content to frameContentWidth", () => {
const lines = frame(["hi"], 20, noTheme);
// Content line: ┃ + 2 pad + content padded to contentWidth + 2 pad + ┃
Expand Down