Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
Elius94 committed Apr 22, 2022
2 parents b0c9d1d + 7340874 commit 8768da1
Showing 1 changed file with 176 additions and 37 deletions.
213 changes: 176 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# console-gui-tools
A simple library to draw option menu or other popup inputs and layout on Node.js console.
A simple library to draw option menu, text popup or other widgets and layout on a Node.js console.

[![npm version](https://badge.fury.io/js/console-gui-tools.svg)](https://npmjs.com/package/console-gui-tools) [![npm](https://img.shields.io/npm/dt/console-gui-tools)](https://npmjs.com/package/console-gui-tools) ![npm bundle size](https://img.shields.io/bundlephobia/min/console-gui-tools) ![GitHub](https://img.shields.io/github/license/elius94/console-gui-tools)

# console-gui-tools
A simple Node.js library to create Console Apps like wizard (or maybe if you like old style colored screen or something like "teletext" programs 😂)
A simple Node.js library to create Console Apps like a wizard (or maybe if you like old style colored screen or something like "teletext" programs 😂)
Apart from jokes, it is a library that allows you to create a screen divided into a part with everything you want to see (such as variable values) and another in which the logs run.
Moreover in this way the application is managed by the input event "keypressed" to which each key corresponds to a bindable command.
For example, to change variables you can open popups with an option selector or with a textbox.
It's in embryonic phase, any suggestion will be constructive :D

![Animation](https://user-images.githubusercontent.com/14907987/162479866-e53f0634-8e96-4c23-9f32-ee920b7cdf2f.gif)
![Animation](https://user-images.githubusercontent.com/14907987/164765317-062c0fe9-7af3-4aa5-a96e-9407a9245341.gif)


[![Readme Card](https://github-readme-stats.vercel.app/api/pin/?username=elius94&repo=console-gui-tools&theme=github_dark&show_icons=true)](https://github.com/Elius94/console-gui-tools) [![https://nodei.co/npm/console-gui-tools.png?downloads=true&downloadRank=true&stars=true](https://nodei.co/npm/console-gui-tools.png?downloads=true&downloadRank=true&stars=true)](https://www.npmjs.com/package/console-gui-tools)
Expand Down Expand Up @@ -40,55 +40,61 @@ To enable the border of the layout and the title.
Example of usage:
```js
// Import module with ES6 syntax
import { ConsoleManager, OptionPopup, InputPopup } from '../index.js'
import { ConsoleManager, OptionPopup, InputPopup, PageBuilder, ButtonPopup, ConfirmPopup } from '../src/ConsoleGui.js'
const GUI = new ConsoleManager({
title: 'TCP Simulator', // Title of the console
logsPageSize: 12, // Number of lines to show in logs page
logsPageSize: 8, // Number of lines to show in logs page
changeLayoutKey: 'ctrl+l', // Change layout with ctrl+l to switch to the logs page
})

// Creating a main page updater:
const updateConsole = async() => {
let screen = ""
screen += chalk.yellow(`TCP server simulator app! Welcome...`) + `\n`
screen += chalk.green(`TCP Server listening on ${HOST}:${PORT}`) + `\n`
screen += chalk.green(`Connected clients: `) + chalk.white(`${connectedClients}\n`)
screen += chalk.magenta(`TCP Messages sent: `) + chalk.white(`${tcpCounter}`) + `\n\n`
const p = new PageBuilder()
p.addRow({ text: `TCP server simulator app! Welcome...`, color: 'yellow' })
p.addRow({ text: `TCP Server listening on ${HOST}:${PORT}`, color: 'green' })
p.addRow({ text: `Connected clients:`, color: 'green' }, { text: ` ${connectedClients}`, color: 'white' })
p.addRow({ text: `TCP messages sent:`, color: 'green', bg: 'bgRed', bold: true, italic: true, underline: true }, { text: ` ${tcpCounter}`, color: 'white' })

// Print if simulator is running or not
if (!valueEmitter) {
screen += chalk.red(`Simulator is not running! `) + chalk.white(`press 'space' to start`) + `\n`
p.addRow({ text: `Simulator is not running! `, color: 'red' }, { text: `press 'space' to start`, color: 'white' })
} else {
screen += chalk.green(`Simulator is running! `) + chalk.white(`press 'space' to stop`) + `\n`
p.addRow({ text: `Simulator is running! `, color: 'green' }, { text: `press 'space' to stop`, color: 'white' })
}

// Print mode:
screen += chalk.cyan(`Mode:`) + chalk.white(` ${mode}`) + `\n`;
// Print message frequency:
screen += chalk.cyan(`Message period:`) + chalk.white(` ${period} ms`) + `\n`;
// Print Min and Max
screen += chalk.cyan(`Min:`) + chalk.white(` ${min}`) + `\n`;
screen += chalk.cyan(`Max:`) + chalk.white(` ${max}`) + `\n`;
// Print current values:
screen += chalk.cyan(`Values:`) + chalk.white(` ${values.map(v => v.toFixed(4)).join(' ')}`) + `\n`;
p.addRow({ text: `Mode: `, color: 'cyan' }, { text: `${mode}`, color: 'white' })
// Print message frequency:
p.addRow({ text: `Message period: `, color: 'cyan' }, { text: `${period} ms`, color: 'white' })
// Print Min and Max
p.addRow({ text: `Min: `, color: 'cyan' }, { text: `${min}`, color: 'white' })
p.addRow({ text: `Max: `, color: 'cyan' }, { text: `${max}`, color: 'white' })
// Print current values:
p.addRow({ text: `Values: `, color: 'cyan' }, { text: ` ${values.map(v => v.toFixed(4)).join(' ')}`, color: 'white' })

// Spacer
screen += `\n\n`;
p.addSpacer()

if (lastErr.length > 0) {
screen += lastErr + `\n\n`
p.addRow({ text: lastErr, color: 'red' })
p.addSpacer(2)
}

screen += chalk.bgBlack(`Commands:`) + `\n`;
screen += ` ${chalk.bold('space')} - ${chalk.italic('Start/stop simulator')}\n`;
screen += ` ${chalk.bold('m')} - ${chalk.italic('Select simulation mode')}\n`;
screen += ` ${chalk.bold('s')} - ${chalk.italic('Select message period')}\n`;
screen += ` ${chalk.bold('h')} - ${chalk.italic('Set max value')}\n`;
screen += ` ${chalk.bold('l')} - ${chalk.italic('Set min value')}\n`;
screen += ` ${chalk.bold('q')} - ${chalk.italic('Quit')}\n`;
p.addRow({ text: "Commands:", color: 'white', bg: 'black' })
p.addRow({ text: ` 'space'`, color: 'gray', bold: true }, { text: ` - Start/stop simulator`, color: 'white', italic: true })
p.addRow({ text: ` 'm'`, color: 'gray', bold: true }, { text: ` - Select simulation mode`, color: 'white', italic: true })
p.addRow({ text: ` 's'`, color: 'gray', bold: true }, { text: ` - Select message period`, color: 'white', italic: true })
p.addRow({ text: ` 'h'`, color: 'gray', bold: true }, { text: ` - Set max value`, color: 'white', italic: true })
p.addRow({ text: ` 'l'`, color: 'gray', bold: true }, { text: ` - Set min value`, color: 'white', italic: true })
p.addRow({ text: ` 'q'`, color: 'gray', bold: true }, { text: ` - Quit`, color: 'white', italic: true })

GUI.setHomePage(screen)
GUI.setHomePage(p)
}

GUI.on("exit", () => {
closeApp()
})

// And manage the keypress event from the library
GUI.on("keypressed", (key) => {
switch (key.name) {
Expand All @@ -109,9 +115,15 @@ GUI.on("keypressed", (key) => {
break
case 's':
new OptionPopup("popupSelectPeriod", "Select simulation period", periodList, period).show().on("confirm", (_period) => {
period = _period
GUI.warn(`NEW PERIOD: ${period}`)
drawGui()
new ButtonPopup("popupConfirmPeriod", "Confirm period", `Period set to ${period} ms, apply?`, ["Yes", "No", "?"]).show().on("confirm", (answer) => {
if (answer === "Yes") {
period = _period
GUI.warn(`NEW PERIOD: ${period}`)
} else if (answer === "?") {
GUI.info(`Choose ok to confirm period`)
}
drawGui()
})
})
break
case 'h':
Expand All @@ -129,7 +141,7 @@ GUI.on("keypressed", (key) => {
})
break
case 'q':
closeApp()
new ConfirmPopup("popupQuit", "Are you sure you want to quit?").show().on("confirm", () => closeApp())
break
default:
break
Expand All @@ -142,6 +154,88 @@ const drawGui = () => {

```

## How to draw the application page?

## NEW DRAWING ALGORYTM

![Animation](https://user-images.githubusercontent.com/14907987/164305847-ea699cba-bb40-46a2-88ea-01496d73b8b1.gif)

All the page is prerendered before printing on the console to prevent noisy flickering.

Introduced new styling design pattern:

Each page need to be created with the new class
```js
const p = new PageBuilder()
```
and to add a styled row it's neccessary to call:
```js
p.addRow({ text: ` 'm'`, color: 'gray', bold: true }, { text: ` - Select simulation mode`, color: 'white', italic: true })
```
The arguments of that function is an array of object (function arguments syntax, no []!), so in a row you can add different phrases with different styles.

The styles are converted to the Chalk modificator:

### colors:
- black
- red
- green
- yellow
- blue
- magenta
- cyan
- white
- blackBright (alias: gray, grey)
- redBright
- greenBright
- yellowBright
- blueBright
- magentaBright
- cyanBright
- whiteBright

### Background colors ('bg')
- bgBlack
- bgRed
- bgGreen
- bgYellow
- bgBlue
- bgMagenta
- bgCyan
- bgWhite
- bgBlackBright (alias: bgGray, bgGrey)
- bgRedBright
- bgGreenBright
- bgYellowBright
- bgBlueBright
- bgMagentaBright
- bgCyanBright
- bgWhiteBright

### Formatters (Each is a prop):
- italic
- bold
- dim
- underline
- overline
- inverse
- hidden
- strikethrough

eg:

```js
p.addRow({ text: `TCP messages sent:`, color: 'green', bg: 'bgRed', bold: true, italic: true, underline: true }, { text: ` ${tcpCounter}`, color: 'white' })
```

And so, we can add the PageBuilder to the home page

```js
GUI.setHomePage(p)
```

The new Screen class is used internally by the ConsoleManager.

## To create an option popup (select)
```js
new OptionPopup("popupSelectPeriod", "Select simulation period", periodList, period).show().on("confirm", (_period) => {
Expand All @@ -150,6 +244,7 @@ new OptionPopup("popupSelectPeriod", "Select simulation period", periodList, per
drawGui()
})
```

### Class OptionPopup:
constructor(id, title, options, selected)
- id: string
Expand All @@ -162,7 +257,8 @@ The result is this:

![Animation](https://user-images.githubusercontent.com/14907987/162480195-b08b4a0b-5d10-4122-8bff-9210295aac1f.gif)

Pressing enter it will close the popup and set the new value
Pressing enter it will close the popup and set the new value. If the list is too long, it will scroll reaching the bottom or top.
Now you can also use "pageup" amd "pagedown" keys to navigate faster.

## To create an input popup (numeric or string)
```js
Expand All @@ -187,6 +283,46 @@ You can use it for example to set a numeric threshold:
If you set isNumeric to true, only numbers are allowed.
All class of components will be destroyed when the popup is closed. The event listeners are removed from the store. Then the garbage collector will clean the memory.

## To create a button popup
```js
new ButtonPopup("popupConfirmPeriod", "Confirm period", `Period set to ${period} ms, apply?`, ["Yes", "No", "?"]).show().on("confirm", (answer) => {
if (answer === "Yes") {
period = _period
GUI.warn(`NEW PERIOD: ${period}`)
} else if (answer === "?") {
GUI.info(`Choose ok to confirm period`)
}
drawGui()
})
```

### Class ButtonPopup:
constructor(id, title, message, buttons = ["Ok", "Cancel", "?"])
- id: string
- title: string
- message: string
- buttons: Array<string> - The text of the buttons

You can use it for example to make a question:

![Animation](https://user-images.githubusercontent.com/14907987/164768181-48f18d25-d05a-4959-88ec-8ce93212e356.gif)

## To create a confirm popup (if you only need a yes or no answer)
```js
new ConfirmPopup("popupQuit", "Are you sure you want to quit?").show().on("confirm", () => closeApp())
```

### Class ConfirmPopup:
constructor(id, title)
- id: string
- title: string

You can use it for example to confirm before quit the app:

![Animation](https://user-images.githubusercontent.com/14907987/164768797-3f538673-78da-4f67-b2c3-be1319f2fb95.gif)

All class of components will be destroyed when the popup is closed. The event listeners are removed from the store. Then the garbage collector will clean the memory.

## Console.log and other logging tools
To log you have to use the following functions:

Expand All @@ -196,7 +332,7 @@ GUI.warn(`NEW MIN VALUE: ${min}`)
GUI.error(`NEW MIN VALUE: ${min}`)
GUI.info(`NEW MIN VALUE: ${min}`)
```
And they written to the bottom of the page.
And then written to the bottom of the page.

![Animation](https://user-images.githubusercontent.com/14907987/162482192-042d88e5-f810-4523-8f0d-1d87a573d1b1.gif)

Expand All @@ -212,9 +348,12 @@ This library is in development now. New componets will come asap.
## License and copyright

MIT License Copyright (c) 2022 [Elia Lazzari](https://github.com/Elius94)

Colors and styles are managed using [Chalk](https://github.com/chalk/chalk)
![image](https://user-images.githubusercontent.com/14907987/164770011-d29579ad-e681-43b2-b550-7fb52fd74021.png)

## Code Documentation

To see the code documentation, please click on the following link:

[Code documentation](DOCS.md)
[Code documentation](DOCS.md)

0 comments on commit 8768da1

Please sign in to comment.