mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-21 20:04:55 +00:00
Add padding to Text component and fix padding calculation
- Add paddingX and paddingY support to Text component (default 1, 1) - Fix padding calculation bug in both Text and Markdown - Right padding now correctly fills to terminal width - Remove unused Spacer import from chat-simple
This commit is contained in:
parent
5f19dd62c7
commit
9dab1192ad
3 changed files with 45 additions and 18 deletions
|
|
@ -111,8 +111,8 @@ export class Markdown implements Component {
|
||||||
for (const line of wrappedLines) {
|
for (const line of wrappedLines) {
|
||||||
// Calculate visible length (strip ANSI codes)
|
// Calculate visible length (strip ANSI codes)
|
||||||
const visibleLength = stripVTControlCharacters(line).length;
|
const visibleLength = stripVTControlCharacters(line).length;
|
||||||
// Right padding to fill to width (accounting for left padding)
|
// Right padding to fill to width (accounting for left padding and content)
|
||||||
const rightPadLength = Math.max(0, width - visibleLength - this.paddingX * 2);
|
const rightPadLength = Math.max(0, width - this.paddingX - visibleLength);
|
||||||
const rightPad = " ".repeat(rightPadLength);
|
const rightPad = " ".repeat(rightPadLength);
|
||||||
|
|
||||||
// Add left padding, content, and right padding
|
// Add left padding, content, and right padding
|
||||||
|
|
|
||||||
|
|
@ -56,13 +56,26 @@ export class Container implements Component {
|
||||||
* Text component - displays multi-line text with word wrapping
|
* Text component - displays multi-line text with word wrapping
|
||||||
*/
|
*/
|
||||||
export class Text implements Component {
|
export class Text implements Component {
|
||||||
constructor(private text: string = "") {}
|
private paddingX: number; // Left/right padding
|
||||||
|
private paddingY: number; // Top/bottom padding
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private text: string = "",
|
||||||
|
paddingX: number = 1,
|
||||||
|
paddingY: number = 1,
|
||||||
|
) {
|
||||||
|
this.paddingX = paddingX;
|
||||||
|
this.paddingY = paddingY;
|
||||||
|
}
|
||||||
|
|
||||||
setText(text: string): void {
|
setText(text: string): void {
|
||||||
this.text = text;
|
this.text = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
render(width: number): string[] {
|
render(width: number): string[] {
|
||||||
|
// Calculate available width for content (subtract horizontal padding)
|
||||||
|
const contentWidth = Math.max(1, width - this.paddingX * 2);
|
||||||
|
|
||||||
if (!this.text) {
|
if (!this.text) {
|
||||||
return [""];
|
return [""];
|
||||||
}
|
}
|
||||||
|
|
@ -71,7 +84,7 @@ export class Text implements Component {
|
||||||
const textLines = this.text.split("\n");
|
const textLines = this.text.split("\n");
|
||||||
|
|
||||||
for (const line of textLines) {
|
for (const line of textLines) {
|
||||||
if (line.length <= width) {
|
if (line.length <= contentWidth) {
|
||||||
lines.push(line);
|
lines.push(line);
|
||||||
} else {
|
} else {
|
||||||
// Word wrap
|
// Word wrap
|
||||||
|
|
@ -81,7 +94,7 @@ export class Text implements Component {
|
||||||
for (const word of words) {
|
for (const word of words) {
|
||||||
if (currentLine.length === 0) {
|
if (currentLine.length === 0) {
|
||||||
currentLine = word;
|
currentLine = word;
|
||||||
} else if (currentLine.length + 1 + word.length <= width) {
|
} else if (currentLine.length + 1 + word.length <= contentWidth) {
|
||||||
currentLine += " " + word;
|
currentLine += " " + word;
|
||||||
} else {
|
} else {
|
||||||
lines.push(currentLine);
|
lines.push(currentLine);
|
||||||
|
|
@ -95,7 +108,33 @@ export class Text implements Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return lines.length > 0 ? lines : [""];
|
// Add padding to each line
|
||||||
|
const leftPad = " ".repeat(this.paddingX);
|
||||||
|
const paddedLines: string[] = [];
|
||||||
|
|
||||||
|
for (const line of lines) {
|
||||||
|
const rightPadLength = Math.max(0, width - this.paddingX - line.length);
|
||||||
|
const rightPad = " ".repeat(rightPadLength);
|
||||||
|
paddedLines.push(leftPad + line + rightPad);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add top padding (empty lines)
|
||||||
|
const emptyLine = " ".repeat(width);
|
||||||
|
const topPadding: string[] = [];
|
||||||
|
for (let i = 0; i < this.paddingY; i++) {
|
||||||
|
topPadding.push(emptyLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add bottom padding (empty lines)
|
||||||
|
const bottomPadding: string[] = [];
|
||||||
|
for (let i = 0; i < this.paddingY; i++) {
|
||||||
|
bottomPadding.push(emptyLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combine top padding, content, and bottom padding
|
||||||
|
const result = [...topPadding, ...paddedLines, ...bottomPadding];
|
||||||
|
|
||||||
|
return result.length > 0 ? result : [""];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import { CombinedAutocompleteProvider } from "../src/autocomplete.js";
|
||||||
import { Editor } from "../src/components-new/editor.js";
|
import { Editor } from "../src/components-new/editor.js";
|
||||||
import { Loader } from "../src/components-new/loader.js";
|
import { Loader } from "../src/components-new/loader.js";
|
||||||
import { Markdown } from "../src/components-new/markdown.js";
|
import { Markdown } from "../src/components-new/markdown.js";
|
||||||
import { Spacer } from "../src/components-new/spacer.js";
|
|
||||||
import { ProcessTerminal } from "../src/terminal.js";
|
import { ProcessTerminal } from "../src/terminal.js";
|
||||||
import { Text, TUI } from "../src/tui-new.js";
|
import { Text, TUI } from "../src/tui-new.js";
|
||||||
|
|
||||||
|
|
@ -74,31 +73,21 @@ editor.onSubmit = (value: string) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trimmed) {
|
if (trimmed) {
|
||||||
// Mark as responding and disable submit
|
|
||||||
isResponding = true;
|
isResponding = true;
|
||||||
editor.disableSubmit = true;
|
editor.disableSubmit = true;
|
||||||
|
|
||||||
// Add user message with custom gray background (similar to Claude.ai)
|
|
||||||
const userMessage = new Markdown(value, undefined, undefined, { r: 52, g: 53, b: 65 });
|
const userMessage = new Markdown(value, undefined, undefined, { r: 52, g: 53, b: 65 });
|
||||||
|
|
||||||
// Insert before the editor (which is last)
|
|
||||||
const children = tui.children;
|
const children = tui.children;
|
||||||
children.splice(children.length - 1, 0, userMessage);
|
children.splice(children.length - 1, 0, userMessage);
|
||||||
children.splice(children.length - 1, 0, new Spacer());
|
|
||||||
|
|
||||||
// Add loader
|
|
||||||
const loader = new Loader(tui, "Thinking...");
|
const loader = new Loader(tui, "Thinking...");
|
||||||
const loaderSpacer = new Spacer();
|
|
||||||
children.splice(children.length - 1, 0, loader);
|
children.splice(children.length - 1, 0, loader);
|
||||||
children.splice(children.length - 1, 0, loaderSpacer);
|
|
||||||
|
|
||||||
tui.requestRender();
|
tui.requestRender();
|
||||||
|
|
||||||
// Simulate a 1 second delay
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// Remove loader and its spacer
|
|
||||||
tui.removeChild(loader);
|
tui.removeChild(loader);
|
||||||
tui.removeChild(loaderSpacer);
|
|
||||||
|
|
||||||
// Simulate a response
|
// Simulate a response
|
||||||
const responses = [
|
const responses = [
|
||||||
|
|
@ -116,7 +105,6 @@ editor.onSubmit = (value: string) => {
|
||||||
// Add assistant message with no background (transparent)
|
// Add assistant message with no background (transparent)
|
||||||
const botMessage = new Markdown(randomResponse);
|
const botMessage = new Markdown(randomResponse);
|
||||||
children.splice(children.length - 1, 0, botMessage);
|
children.splice(children.length - 1, 0, botMessage);
|
||||||
children.splice(children.length - 1, 0, new Spacer());
|
|
||||||
|
|
||||||
// Re-enable submit
|
// Re-enable submit
|
||||||
isResponding = false;
|
isResponding = false;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue