Skip to content

DoubledDoge/consoleprism

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

99 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

ConsolePrism

CI/CD CodeQL NuGet License: MIT .NET Downloads

An opinionated, component-based UI framework for .NET console applications. Build terminal interfaces with tables, menus, progress bars, spinners, layout containers, and more.


๐Ÿ“‘ Table of Contents


๐Ÿš€ Features

  • Theming System โ€” Fully composable themes combining colour schemes and border styles, with built-in presets
  • Semantic Colour Output โ€” Contextual coloured text for errors, success, warnings, and information
  • Rich Components โ€” Tables, menus, progress bars, spinners, and notifications
  • Layout Containers โ€” Panel, Row, Column, and Viewport for structured terminal layouts
  • Renderer Abstraction โ€” Swap rendering backends for testing or deferred output via IRenderer
  • Scoped Theming โ€” Apply themes globally or per-component, with scoped overrides via ConsoleContext

๐Ÿ“ฆ Installation

NuGet Package

dotnet add package ConsolePrism

Manual Installation

  1. Clone the repository
  2. Add a reference to your project:
dotnet add reference path/to/src/ConsolePrism.csproj

๐Ÿ“š Usage Guide

Semantic Colour Output

using ConsolePrism.Core;

ColorWriter.WriteSuccessLine("Operation completed!");
ColorWriter.WriteErrorLine("Something went wrong.");
ColorWriter.WriteWarningLine("Proceed with caution.");
ColorWriter.WriteInfoLine("Here is some information.");
ColorWriter.WriteHighlightLine("Important text.");

// Explicit colour when needed
ColorWriter.WriteColoredLine("Custom text", ConsoleColor.Magenta);

Menus

using ConsolePrism.Components;

// Arrow-key interactive menu (default)
string[] choices = ["New Game", "Continue", "Settings", "Exit"];

Menu interactive = new("Main Menu", MenuStyle.Interactive, choices);

int choice = interactive.Interact();

// Numbered menu
Menu numbered = new("Select Difficulty", MenuStyle.Numbered, "Easy", "Normal", "Hard");

int difficulty = numbered.Interact();

// Bordered menu
Menu bordered = new("Choose Mode", MenuStyle.Bordered, "Story", "Creative", "Survival");

int mode = bordered.Interact();

Tables

using ConsolePrism.Components;

string[] headers = ["Name", "Score", "Level"];
string[][] data = [
    ["Alice",   "1250", "10"],
    ["Bob",     "980",  "8" ],
    ["Charlie", "1500", "12"],
]; // Can be nullable for empty cells

new Table(headers, data).Render();

// Alternatively for coloured cells
TableCell[][] colouredData = [
    ["Alice",   new TableCell("1250", ConsoleColor.Green), "10"],
    ["Bob",     new TableCell("980", ConsoleColor.Red),    "8" ],
    ["Charlie", new TableCell("1500", ConsoleColor.Yellow),"12"],
];

new Table(headers, colouredData).Render();

// Custom column widths
int[] widths = [15, 10, 8];
new Table(headers, data, widths).Render();

Progress Bars

using ConsolePrism.Components;

// Static progress bar
new ProgressBar(75, "Processing", 100).Render();

// Animated in-place progress
ProgressBar bar = new(0, "Loading", 100) { InPlace = true };

for (int i = 0; i <= 100; i++)
{
    bar.Current = i;
    bar.Render();
    Thread.Sleep(50);
}

Spinners

using ConsolePrism.Components;

Spinner spinner = new(Spinner.Dots, "Loading assets...");
spinner.Start();

// Do work...
await LoadAssetsAsync();

spinner.Stop("Assets loaded successfully!");

// Using Dispose pattern
using Spinner spinner = new(Spinner.Pulse, "Connecting...");
spinner.Start();
await ConnectAsync();

Notifications

using ConsolePrism.Components;

new Notification("File saved!", false, NotificationLevel.Success).Render();
new Notification("Low disk space.", false, NotificationLevel.Warning).Render();
new Notification("Connection failed.", false NotificationLevel.Error).Render();

// Transient notification
new Notification("Autosaving...", false, NotificationLevel.Info, 2000).Render();

// Bordered notification
new Notification("Welcome to ConsolePrism!", true, NotificationLevel.Info).Render();

Console Text

using ConsolePrism.Components;

// Simple text
new ConsoleText("This is a simple text component.").Render();

// Text with colour
new ConsoleText("This is an error message.", ConsoleColor.Red).Render();

// Note: This has been implemented with the sole purpose of for ease of use in the panel, column, row and viewport layouts.

Panels

using ConsolePrism.Layout;

Panel simplePanel = new(
	content: new ConsoleText("This is a simple panel.") // Or any component
);

// Complex panel with title, content, and padding
Panel panel = new(
    title: "Welcome",
    content: new ConsoleText("Hello, World!"),
    horizontalPadding: 2,
    verticalPadding: 1
);

panel.Render();

Rows

using ConsolePrism.Layout;

Row row = new(
	spacing: 1,
	new ConsoleText("Header"),
	new Panel(title: "Info", content: new ConsoleText("Details...")),
	new ConsoleText("Footer")
);

row.Render();

// Alternatively through Fluent API:
Row fluentRow = new Row(spacing: 1)
    .Add(new ConsoleText("Header"))
    .Add(new Panel(title: "Info", content: new ConsoleText("Details...")))
    .Add(new ConsoleText("Footer"));

fluentRow.Render();

Viewport

using ConsolePrism.Layout;

Viewport viewport = new(
	height: 2,
	new ConsoleText("Line 1"),
	new ConsoleText("Line 2"),
	new ConsoleText("Line 3"),
	new ConsoleText("Line 4"),
	new ConsoleText("Line 5")
);

viewport.Render();

// Alternatively through Fluent API:
Viewport fluentViewport = new Viewport(height: 10)
    .Add(new ConsoleText("Line 1"))
    .Add(new ConsoleText("Line 2"))
    // ... 50+ more lines
    .Add(new ConsoleText("Line 52"));

fluentViewport.Render();  // Initially shows lines 1-10

// User can scroll
fluentViewport.ScrollDown(3);  // Now shows lines 4-13
fluentViewport.Render();

fluentViewport.ScrollUp(1);    // Back to lines 3-12
fluentViewport.Render();

fluentViewport.ScrollToTop();  // Back to lines 1-10
fluentViewport.Render();

// Users can also interact with the viewport itself through up/down arrow keys:
fluenViewport.Interact();

Columns

using ConsolePrism.Layout;

Column column = new(
	gap: 2,
	new Panel(title: "Left", content: new ConsoleText("A")),
	new Panel(title: "Middle", content: new ConsoleText("B")),
	new Panel(title: "Right", content: new ConsoleText("C"))
);		

column.Render();

// Alternatively through Fluent API:
Column fluentColumn = new Column(gap: 2)
    .Add(new Panel(title: "Left", content: new ConsoleText("A")))
    .Add(new Panel(title: "Middle", content: new ConsoleText("B")))
    .Add(new Panel(title: "Right", content: new ConsoleText("C")));

fluentColumn.Render();

App Shell

using ConsolePrism.Layout;
using ConsolePrism.Components;

Panel mainContent = new(
    title: "Dashboard",
    content: new ConsoleText("Welcome to the application!"),
    horizontalPadding: 2
);

// Wrap the content in the AppShell
AppShell shell = new(
    title: "MY AWESOME CLI",
    content: mainContent,
    leftFooter: "Status: Online",
    rightFooter: "v1.0.0 | Press ESC to exit"
);

shell.Render();

Console Utilities

using ConsolePrism.Core;

// Positioning
ConsoleHelper.WriteCentered("Centered Title");
ConsoleHelper.WriteRight("Right-aligned", padding: 2);
ConsoleHelper.WriteAt("Positioned text", x: 10, y: 5);

// Cursor control
ConsoleHelper.HideCursor();
ConsoleHelper.MoveCursor(0, 10);
ConsoleHelper.ShowCursor();

// Drawing
ConsoleHelper.DrawHorizontalLine('โ”€');
ConsoleHelper.WriteEmptyLines(2);

๐ŸŽจ Theming

List of available theme presets:

  • NordTheme - Arctic blue tones with rounded borders
  • MonochromeTheme - Grayscale for minimal or accessible output
  • RetroTheme - Amber tones with ASCII borders
  • MatrixTheme - Cascading greens against a dark background
  • SunsetTheme - Cosy oranges, magenta and soft whites to evoke a twilight atmosphere
  • SolarizedTheme - Warm amber and earthy tones with cool accent colours
  • PastelTheme - Muted, light tones for a gentle visual experience

Applying a Built-in Preset

using ConsolePrism.Themes;
using ConsolePrism.Themes.Presets;

// Apply globally
Theme.Apply(NordTheme.Instance);

// Reset to default
Theme.Apply(Theme.Default);

Creating a Custom Theme

using ConsolePrism.Themes;

Theme myTheme = new()
{
    Colors = new ColorScheme
    {
        Primary   = ConsoleColor.Cyan,
        Success   = ConsoleColor.Green,
        Error     = ConsoleColor.Red,
        Warning   = ConsoleColor.Yellow,
        Info      = ConsoleColor.Blue,
        Highlight = ConsoleColor.Magenta,
        Muted     = ConsoleColor.DarkGray,

        MenuTitle    = ConsoleColor.Cyan,
        MenuOption   = ConsoleColor.White,
        MenuSelected = ConsoleColor.Green,
        MenuBorder   = ConsoleColor.DarkGray,

        TableHeader  = ConsoleColor.Cyan,
        TableBorder  = ConsoleColor.DarkGray,
        TableData    = ConsoleColor.White,

        ProgressBarComplete   = ConsoleColor.Green,
        ProgressBarIncomplete = ConsoleColor.DarkGray,
        ProgressBarText       = ConsoleColor.White
    },
    Border = BorderStyle.Rounded
};

Theme.Apply(myTheme);

Scoped Theme Override

using ConsolePrism.Core;
using ConsolePrism.Themes.Presets;

// Theme.Current is temporarily replaced for the duration of the block
using (new ConsoleContext(MonochromeTheme.Instance))
{
    table.Render();
}
// Theme.Current is automatically restored here

Per-Component Theme Override

Table table = new(headers, data)
{
    Theme = RetroTheme.Instance
};

table.Render(); // uses RetroTheme regardless of Theme.Current

Border Styles

using ConsolePrism.Themes;

// Built-in presets
BorderStyle.Single;   // โ”Œโ”€โ” โ”‚ โ””โ”€โ”˜  (default)
BorderStyle.Double;   // โ•”โ•โ•— โ•‘ โ•šโ•โ•
BorderStyle.Rounded;  // โ•ญโ”€โ•ฎ โ”‚ โ•ฐโ”€โ•ฏ
BorderStyle.Ascii;    // +-+ | +-+

// Custom border
Borderstyle custom = new()
{
    TopLeft  = 'โ•”', TopRight  = 'โ•—',
    BottomLeft = 'โ•š', BottomRight = 'โ•',
    Horizontal = 'โ•', Vertical = 'โ•‘',
    Cross = 'โ•ฌ',
    TeeLeft = 'โ• ', TeeRight = 'โ•ฃ',
    TeeTop  = 'โ•ฆ', TeeBottom = 'โ•ฉ'
};

๐Ÿ—๏ธ Architecture

ConsolePrism/
โ”œโ”€โ”€ Interfaces/
โ”‚   โ”œโ”€โ”€ IRenderable       โ†’ Anything that can render itself
โ”‚   โ”œโ”€โ”€ IInteractable     โ†’ Components that accept user input
โ”‚   โ”œโ”€โ”€ IComponent        โ†’ Base interface for all UI components
|   โ””โ”€โ”€ IRenderer         โ†’ Output backend abstraction
โ”‚
โ”œโ”€โ”€ Themes/
โ”‚   โ”œโ”€โ”€ ColorScheme       โ†’ Full color palette definition
โ”‚   โ”œโ”€โ”€ BorderStyle       โ†’ Border character set definition
โ”‚   โ”œโ”€โ”€ Theme             โ†’ Unified theme object (ColorScheme + BorderStyle)
โ”‚   โ””โ”€โ”€ Presets/
โ”‚
โ”œโ”€โ”€ Core/
โ”‚   โ”œโ”€โ”€ ColorWriter       โ†’ Semantic colored text output
โ”‚   โ”œโ”€โ”€ ConsoleHelper     โ†’ Cursor control, positioning, and drawing utilities
โ”‚   โ”œโ”€โ”€ ConsoleContext    โ†’ Scoped theme switching via IDisposable
โ”‚   โ””โ”€โ”€ Rendering/
โ”‚       โ”œโ”€โ”€ ConsoleRenderer   โ†’ Default implementation writing to Console
โ”‚       โ””โ”€โ”€ StringRenderer    โ†’ In-memory buffer for testing and layout buffering
โ”‚
โ”œโ”€โ”€ Components/
|   โ”œโ”€โ”€ ComponentBase     โ†’ Abstract base with theme resolution and renderer swapping
โ”‚   โ”œโ”€โ”€ Menu              โ†’ Numbered, interactive, and bordered menu styles
โ”‚   โ”œโ”€โ”€ Table             โ†’ Auto-sizing bordered table with text wrapping
|   โ”œโ”€โ”€ TableCell         โ†’ Cell content with optional colour
โ”‚   โ”œโ”€โ”€ ProgressBar       โ†’ Static and in-place animated progress bars
โ”‚   โ”œโ”€โ”€ Spinner           โ†’ Animated spinners for async operations
โ”‚   โ”œโ”€โ”€ Notification      โ†’ Transient styled messages with optional auto-dismiss
|   โ”œโ”€โ”€ ConsoleText       โ†’ Simple text for use with the layout components
โ”‚   โ””โ”€โ”€ Prompt            โ†’ Styled input prompt with optional masked entry
โ”‚
โ””โ”€โ”€ Layout/
    โ”œโ”€โ”€ Panel             โ†’ Bordered content container with title support
    โ”œโ”€โ”€ Row               โ†’ Vertical component stacking with optional spacing
    โ”œโ”€โ”€ Column            โ†’ Horizontal side-by-side component layout
    โ”œโ”€โ”€ AppShell          โ†’ Common application layout with header, footer, and main content
    โ””โ”€โ”€ Viewport          โ†’ Scrollable content region with fixed visible height

๐Ÿ’ป Requirements

  • .NET 9.0 or .NET 10.0
  • Windows, macOS, or Linux
  • A terminal with a dark background is recommended for the best visual experience

๐Ÿ“„ Licence

See LICENCE for details. (MIT Licence)


๐Ÿค Contributing

Contributions are welcome! You can:

  • Report bugs or request features via Issues
  • Submit pull requests
  • Suggest improvements to the API
  • Propose new components, themes, or layout containers

About

Another opinionated console UI framework for .NET applications.

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages