Skip to content

deepraj02/konsole

Repository files navigation

Konsole - A lightweight TUI framework for Dart 🎯

A modern, feature-rich terminal UI framework for Dart. Build interactive command-line interfaces with ease using a component-based architecture.

Konsole provides a simple yet powerful way to create terminal applications with rich UI components like boxes, buttons, spinners, and more.

Example

Example

Konsole Demo 1
Basic Components Demo
Konsole Demo 2
Interactive Components
Konsole Demo 3
TUI Counter App with Konsole
## Features
  • 🎨 Rich component library - Buttons, boxes, spinners, text labels, and more
  • 📊 Flexible layout system - Use rows and columns for intuitive layouts
  • 🎯 Focus management - Tab navigation between interactive elements
  • 🌈 ANSI color support - Full terminal color customization
  • ⌨️ Input handling - Process keyboard input from your users
  • 🔄 Update loop - Automatic rendering with animation support

Installation

Add Konsole to your pubspec.yaml:

dependencies:
  konsole: ^1.0.0

Then run:

dart pub get

Core Concepts

Konsole is built around a few simple concepts:

  • Components: UI elements like Button, Text, Box
  • Layouts: Row and Column components for organizing elements
  • Application: The main Konsole class that manages components and rendering
  • Input Handling: Each component can respond to user input

Components

Basic Components

Component Description
Text Simple text display with color support
Button Interactive button with callback support
Box Container with border and optional title
Spinner Animated loading indicator with multiple styles

More to come.

Layout Components

Component Description
Row Horizontal layout container
Column Vertical layout container

Usage

Simple Example

import 'package:konsole/konsole.dart';

void main() {
  final app = Konsole();
  app.add(Text.success("Hello Konsole!"));
  app.run();
}

Text Styles Example

See example/components/texts.dart for a full showcase of all text styles and extension methods:

import 'package:konsole/konsole.dart';

void main() {
  final examples = [
    Text('Default Text'),
    Text.success('Success Text'),
    Text.error('Error Text'),
    Text.warning('Warning Text'),
    Text.info('Info Text'),
    Text.muted('Muted Text'),
    Text.highlight('Highlight Text'),
    Text.title('Title Text'),
    Text.subtitle('Subtitle Text'),
    Text.accent('Accent Text'),
    Text('Bold Text').bold(),
    Text('Italic Text').italic(),
    Text('Underline Text').underline(),
    Text('Custom Color').withColor(KonsoleColors.magenta),
    Text('Custom BG').withBackgroundColor(KonsoleColors.bgCyan),
    Text('Right Aligned', alignment: TextAlignment.right, maxWidth: 30),
    Text('Center Aligned', alignment: TextAlignment.center, maxWidth: 30),
    Text(
      'Wrapped text example that is long enough to demonstrate word wrapping.',
      maxWidth: 20,
      wordWrap: true,
    ),
    Text('With Prefix', prefix: '>> '),
    Text('With Suffix', suffix: ' <<'),
  ];

  final app = Konsole();
  app.add(Column(examples));
  app.run();
}

Interactive Counter Example

See example/apps/konsole_example.dart for a full-featured interactive demo with counter, spinners, and more.

Complex Layout Example

import 'package:konsole/konsole.dart';

class Counter extends KonsoleComponent {
  int value;
  String fgColor;
  String? bgColor;
  int totalWidth;

  Counter({
    this.value = 0,
    this.fgColor = KonsoleColors.white,
    this.bgColor,
    this.totalWidth = 20,
    super.marginHorizontal,
    super.marginVertical,
  }) : super(width: totalWidth, height: 1) {
    focusable = true;
  }

  @override
  String render() {
    String text = 'Counter: $value';
    text =
        text.length > totalWidth
            ? text.substring(0, totalWidth)
            : text.padRight(totalWidth);
    return Ansi.color(text, fg: fgColor, bgColor: bgColor);
  }

  @override
  void handleInput(String input) {
    if (focused) {
      if (input == '\x1B[A') value++;
      if (input == '\x1B[B') value--;
    }
  }
}



void main() {
  final app = Konsole();

  final counter = Counter(fgColor: KonsoleColors.red, totalWidth: 35);

  final counterBox = Column([
    counter,
    Column([
      Button(
        'Up',
        fgColor: KonsoleColors.magenta,
        onPressed: () => counter.value++,
        customWidth: 10,
      ),
      Button(
        'Down',
        fgColor: KonsoleColors.yellow,
        onPressed: () => counter.value--,
        customWidth: 10,
      ),
    ]),
  ]);

  app.add(
    Row([
      counterBox,
      Column([
        Spinner.line(fgColor: KonsoleColors.cyan),
        Spinner.dot(fgColor: KonsoleColors.yellow),
        Spinner.box(fgColor: KonsoleColors.magenta),
        Spinner(fgColor: KonsoleColors.blue),
      ]),
    ]),
  );

  app.run();
}

Component Details

Text

Display styled text with color and formatting support:

Text.success("Success!");
Text.error("Error!");
Text.warning("Warning!");
Text.info("Info");
Text.muted("Muted");
Text.highlight("Highlight");
Text.title("Title");
Text.subtitle("Subtitle");
Text.accent("Accent");

// Use extension methods for chaining styles
Text("Bold").bold();
Text("Italic").italic();
Text("Underline").underline();
Text("Custom Color").withColor(KonsoleColors.magenta);
Text("Custom BG").withBackgroundColor(KonsoleColors.bgCyan);
Text("Right Aligned", alignment: TextAlignment.right, maxWidth: 30);
Text("Center Aligned", alignment: TextAlignment.center, maxWidth: 30);
Text("Wrapped text example that is long enough to demonstrate word wrapping.", maxWidth: 20, wordWrap: true);
Text("With Prefix", prefix: '>> ');
Text("With Suffix", suffix: ' <<');

Button

Interactive button that can respond to user input:

Button(
  "Click Me",
  fgColor: KonsoleColors.white,
  bgColor: KonsoleColors.bgBlue,
  onPressed: () => print("Button clicked!"),
)

Box

Container with border and optional title:

Box(
  Text("Content inside box"),
  title: "Box Title",
  fgColor: KonsoleColors.cyan,
)

Spinner

Animated loading indicators with multiple styles:

// Default spinner '⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'
Spinner(fgColor: KonsoleColors.blue)

// Dot-style spinner '.', '..', '...', '....'
Spinner.dot(fgColor: KonsoleColors.yellow)

// Line-style spinner
Spinner.line(fgColor: KonsoleColors.cyan)

// Box-style spinner  '□', '■', '▣', '▢'
Spinner.box(fgColor: KonsoleColors.magenta)

Counter

Interactive numeric counter:

See example/apps/counter.dart for a full implementation.

Key Navigation

  • Tab: Move focus between interactive components
  • Enter: Activate focused buttons
  • Up/Down Arrow: Interact with counter components
  • q: Quit the application

Color Support

Konsole provides built-in ANSI color constants:

// Foreground colors
KonsoleColors.black
KonsoleColors.red
KonsoleColors.green
KonsoleColors.yellow
KonsoleColors.blue
KonsoleColors.magenta
KonsoleColors.cyan
KonsoleColors.white

// Background colors
KonsoleColors.bgBlack
KonsoleColors.bgRed
KonsoleColors.bgGreen
KonsoleColors.bgYellow
KonsoleColors.bgBlue
KonsoleColors.bgMagenta
KonsoleColors.bgCyan
KonsoleColors.bgWhite

Creating Custom Components

Extend the KonsoleComponent class to create your own components:

class MyCustomComponent extends KonsoleComponent {
  MyCustomComponent({super.marginHorizontal, super.marginVertical}) : super(width: 10, height: 1);

  @override
  String render() {
    return "My custom component";
  }
  
  @override
  void handleInput(String input) {
    // Handle input here
  }
  
  @override
  void update(double dt) {
    // Update state here
  }
}

Layout System

Konsole uses a simple but powerful layout system with two main layout components:

  1. Row: Horizontal layout that arranges components from left to right
  2. Column: Vertical layout that arranges components from top to bottom

Both layout components support margins:

// Horizontal layout with margin
Row([component1, component2], marginHorizontal: 2, marginVertical: 1)

// Vertical layout with margin
Column([component1, component2], marginHorizontal: 2, marginVertical: 1)

Each component can also have its own margins:

Text("Hello", marginHorizontal: 2, marginVertical: 1)

License

This project is licensed under the MIT License - see the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

About

A smol- lightweight TUI Library for Dart

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages